В чем разница между One-Way Binding и Two-Way Binding?
Есть одностороння привязка, когда интерфейс отображает данные из модели, и данные в модели меняются только сверху, т.е. в результате обработки события меняется модель, и в результате рисуется интерфейс с уже новыми данными.
Есть двухсторонняя, когда интерфейс может изменить модель, и в интерфейсе отобразятся новые данные из модели.
Считается что разница в направлении изменения данных, т.е. в одностороннем интерфейс не может менять модель, а в двухстороннем может.
Теперь вопрос на миллион. В любом случае двухсторонний биндинг под капотом имеет привязку к событиям (иначе как изменить модель), т.е. по своей логике это тоже самое, т.е. есть модель, затем подвязываемся на событие, в результате обработки события меняется модель, и затем рисуем интерфейс с новыми данными. Тоже самое, что и односторонняя привязка, только обычно это делается под капотом (вроде Ангуляра), и для разработчиков это видно как «двухсторонняя» привязка.
Так в чем разница между ними?
- Вопрос задан более трёх лет назад
- 2539 просмотров
3 комментария
Простой 3 комментария
Two-way Binding Helpers
Note:
LinkedStateMixin is deprecated as of React v15. The recommendation is to explicitly set the value and change handler, instead of using LinkedStateMixin .
Importing
import LinkedStateMixin from 'react-addons-linked-state-mixin'; // ES6 var LinkedStateMixin = require('react-addons-linked-state-mixin'); // ES5 with npm
LinkedStateMixin is an easy way to express two-way binding with React.
In React, data flows one way: from owner to child. We think that this makes your app’s code easier to understand. You can think of it as «one-way data binding.»
However, there are lots of applications that require you to read some data and flow it back into your program. For example, when developing forms, you’ll often want to update some React state when you receive user input. Or perhaps you want to perform layout in JavaScript and react to changes in some DOM element size.
In React, you would implement this by listening to a «change» event, read from your data source (usually the DOM) and call setState() on one of your components. «Closing the data flow loop» explicitly leads to more understandable and easier-to-maintain programs. See our forms documentation for more information.
Two-way binding — implicitly enforcing that some value in the DOM is always consistent with some React state — is concise and supports a wide variety of applications. We’ve provided LinkedStateMixin : syntactic sugar for setting up the common data flow loop pattern described above, or «linking» some data source to React state .
Note:
LinkedStateMixin is just a thin wrapper and convention around the onChange / setState() pattern. It doesn’t fundamentally change how data flows in your React application.
LinkedStateMixin: Before and After
Here’s a simple form example without using LinkedStateMixin :
var createReactClass = require('create-react-class'); var NoLink = createReactClass( getInitialState: function() return message: 'Hello!'>; >, handleChange: function(event) this.setState(message: event.target.value>); >, render: function() var message = this.state.message; return input type="text" value=message> onChange=this.handleChange> />; > >);
This works really well and it’s very clear how data is flowing, however, with a lot of form fields it could get a bit verbose. Let’s use LinkedStateMixin to save us some typing:
var createReactClass = require('create-react-class'); var WithLink = createReactClass( mixins: [LinkedStateMixin], getInitialState: function() return message: 'Hello!'>; >, render: function() return input type="text" valueLink=this.linkState('message')> />; > >);
LinkedStateMixin adds a method to your React component called linkState() . linkState() returns a valueLink object which contains the current value of the React state and a callback to change it.
valueLink objects can be passed up and down the tree as props, so it’s easy (and explicit) to set up two-way binding between a component deep in the hierarchy and state that lives higher in the hierarchy.
Note that checkboxes have a special behavior regarding their value attribute, which is the value that will be sent on form submit if the checkbox is checked (defaults to on ). The value attribute is not updated when the checkbox is checked or unchecked. For checkboxes, you should use checkedLink instead of valueLink :
There are two sides to LinkedStateMixin : the place where you create the valueLink instance and the place where you use it. To prove how simple LinkedStateMixin is, let’s rewrite each side separately to be more explicit.
valueLink Without LinkedStateMixin
var createReactClass = require('create-react-class'); var WithoutMixin = createReactClass( getInitialState: function() return message: 'Hello!'>; >, handleChange: function(newValue) this.setState(message: newValue>); >, render: function() var valueLink = value: this.state.message, requestChange: this.handleChange >; return input type="text" valueLink=valueLink> />; > >);
As you can see, valueLink objects are very simple objects that just have a value and requestChange prop. And LinkedStateMixin is similarly simple: it just populates those fields with a value from this.state and a callback that calls this.setState() .
LinkedStateMixin Without valueLink
var LinkedStateMixin = require('react-addons-linked-state-mixin'); var createReactClass = require('create-react-class'); var WithoutLink = createReactClass( mixins: [LinkedStateMixin], getInitialState: function() return message: 'Hello!'>; >, render: function() var valueLink = this.linkState('message'); var handleChange = function(e) valueLink.requestChange(e.target.value); >; return input type="text" value=valueLink.value> onChange=handleChange> />; > >);
The valueLink prop is also quite simple. It simply handles the onChange event and calls this.props.valueLink.requestChange() and also uses this.props.valueLink.value instead of this.props.value . That’s it!
Two-way Data Binding in React
In React data flows one-way, from top to bottom. It does not support two-way data binding for good reasons. However, we can use Hooks to implement a pseudo two-way data binding.
Published Dec 29, 2020
Updated Oct 21, 2021
Reading time 3 min
Update October 2021
The post has been rewritten and the StackBlitz demo has been updated to React 17.
One-way vs. Two-way
With two-way data binding the data flows in both directions, from the parent component to the child component and vice versa. Both, the parent and the child, are allowed to mutate data.
With one-way Data Binding the data flows in one direction, from the parent component to the child component. The child component can read the data but is not allowed to update the data directly. Instead, the child component emits an event to the parent and the parent component is responsible for updating the data.
Older frameworks (like AngularJS, which is deprecated) support Two-way Data Binding but modern frameworks like Angular and Vue don’t support this model anymore. They both work with One-way Data Binding.
Handling data binding
Angular and Vue
Angular and Vue provide a convenient for pseudo two-way data binding. This is data binding that looks like two-way data binding but is actually still one-way data binding under the hood. In Angular it is the [(ngModel)] directive, in Vue it is the v-model directive. Both of them provide the data as input (input binding), subscribe to a change event and update the data.
Here is an example of v-model on an input element:
input v-model="firstName" /> input :value="firstName" @input="firstName = $event.target.value" />
React
React does not provide a short-hand syntax for handling two-way data flow. But you can write your own hook.
Implementation
Let’s create our own pseudo two-way data binding hook for an HTML input element.
The hook uses a state variable to store the current value and accepts the initial value as parameter. This allows you to prefill the input element.
function useModel(initial: string = null) const [value, setValue] = useStatestring>(initial); >
Next, we need to add an event handler to the input element to get notified whenever the input value changes. We will then update our state.
function useModel(initial: string = null) // . const handler: ChangeEventHandlerHTMLInputElement> = (e) => setValue(e.currentTarget.value); >; >
Finally, we need to return the value and the event handler. We also return the setValue function to let the component set the value programmatically.
function useModel(initial: string = null) // . const model = value, onChange: handler >; return model, setModel: setValue >; >
That’s it. We can now use this hook in our component. We need to spread the model on our input element (line 7). This will add both the value and the onChange event listener.
function App() const model, setModel > = useModel("John"); const reset = () => setModel(""); return ( > input . model> /> div>Hello model.value>div> button onClick=reset>>Resetbutton> > ); >
The code examples above are shortened. The complete example is available on StackBlitz. It includes TypeScript definitions and a callback function for the change event:
Wrap up
We have created a simple hook for Two-way Data Binding on input elements. The hook subscribes to the change event and stores the current value in a state variable.
It’s of course a very basic example with a simple API. We could improve it and add new features like handling numbers.
While it may look laborious that React does not provide this out of the box as Vue and Angular do, it allows you to create your own custom hook that better suits your needs.
Two way binding react что такое
Akash Mittal Tools / April 26, 2023
React is a fascinating library of JavaScript that simplifies creating frontend and user interface. One of the important aspects is how it binds data with the UI components. Data binding in React can be done through declared variables, props and state. It gives us the flexibility to synchronize both the data as well as UI.
In this article, we will focus on data binding techniques and the differences between them. We will explain the concepts using various examples and use cases.
Types of data binding
There are primarily two types of data binding techniques in React: one-way data binding and two-way data binding. Although there are a few more like context data binding , we will keep our focus on the above two.
One-way data binding
One-way means that the binding happens in one direction. In this case, changes in the data automatically update the UI, but changes in the UI do not automatically update the data. That’s why it is referred to as one-way data binding.
React achieves one-way data binding by using state and props.
Props
Props (short for properties) are the mechanism by which data is passed from a parent component to its children. T hey are read-only, meaning that child components cannot modify the data received from their parent components.
Now since the data is read-only, the child component can’t update it. This is one-way data binding.
function Welcome(props) < returnHello, !
; > function App() < return ; >
State
Components in React can have dynamic behavior by representing their internal data using state, which can be managed in both class and function components.
✅ Initializing state
In class components, state is initialized in the constructor.
class Counter extends React.Component < constructor(props) < super(props); this.state = < count: 0, >; > >
In function components, the useState hook is used to manage state.
import React, < useState >from ‘react’; function Counter()
✅ Updating state with setState
In class components, state is updated using the setState method.
class Counter extends React.Component < // . increment() < this.setState(< count: this.state.count + 1 >); > >
✅ Using state in class components
class Counter extends React.Component < // . render() < return (); > >
✅ Using state in function components with useState hook
import React, < useState >from 'react'; function Counter() < const [count, setCount] = useState(0); function increment() < setCount(count + 1); >return (); >
In the above examples, we have defined state in class as well as functional components. The state data is bound to the UI. At the click of a button, the count will increase which will get reflected in the UI.
Two-way data binding
Two-way data binding allows bidirectional data flow, meaning that changes in the UI automatically update the component’s state, and changes in the state automatically update the UI. In React, two-way data binding is achieved using controlled components.
Controlled components
Controlled components are form elements whose values are controlled by the state. They maintain a consistent, bidirectional data flow between the UI components and the data models.
✅ Understanding controlled components
class Form extends React.Component < constructor(props) < super(props); this.state = < value: '' >; > handleChange(event) < this.setState(< value: event.target.value >); > handleSubmit(event) < // Process form data >render() < return (); > >
✅ Implementing controlled components in function components
import React, < useState >from 'react'; function Form() < const [value, setValue] = useState(''); function handleChange(event) < setValue(event.target.value); >function handleSubmit(event) < // Process form data >return (); >
In the above code, two-way data binding is achieved by binding the value attribute of the input element to the value state variable using the useState hook, and binding the onChange event of the input element to the handleChange function.
When the user types something in the input field, the onChange event of the input element is triggered, which calls the handleChange function. The handleChange function updates the value state variable with the current value of the input field using the setValue function provided by the useState hook.
This update to the value state variable triggers a re-render of the Form component, causing the value attribute of the input element to be updated with the new value of the value state variable. This is how the input field stays in sync with the value state variable, creating one-way data binding.
On the other hand, when the value state variable is updated by some other means, such as by submitting the form, the input element is automatically updated with the new value because it is bound to the value state variable. This is how the value state variable stays in sync with the input field, creating the second half of two-way data binding.
Overall, this two-way data binding allows for seamless interaction between the user and the form, where changes made in the input field are immediately reflected in the state of the component, and vice versa.
Comparing one-way and two-way data binding
Unidirectional data flow | Bidirectional data flow |
UI updates automatically when data changes, but not vice versa | UI and data are automatically in sync |
Uses state and props | Uses controlled components |
Easier to reason about and debug | Provides more control over form elements and validation |
Use cases and examples
✅ Displaying a list of items
To display a list of items on a web page, developers commonly rely on li tags, tables, and data grids, among which Handsontable offers a powerful, and feature-rich data grid solution for React projects.
Explore Handsontable demo for React
Using one-way data binding, you can display a list of items by passing the data through props and rendering it in a child component.
✅ Filtering a list of items
In this example, we demonstrate two-way data binding by implementing a search filter that updates the displayed list of items based on user input.
✅ Creating a form with validation
Combining one-way and two-way data binding techniques, you can create a form with validation that displays error messages based on the current state.
import React, < useState >from 'react'; function FormWithValidation() < const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [errors, setErrors] = useState(<>); function validateForm() < const newErrors = <>; if (!email) < newErrors.email = 'Email is required.'; >if (!password) < newErrors.password = 'Password is required.'; >setErrors(newErrors); return Object.keys(newErrors).length === 0; > function handleSubmit(event) < event.preventDefault(); if (validateForm()) < // Process form data >> return (); > function App() < return ; >
In this example, we use two-way data binding to control form input values and one-way data binding to display validation messages based on the current state.
Advanced data binding techniques
Let’s explore how we can utilize some advanced techniques in React to create more complex and flexible applications beyond one-way and two-way data binding.
✅ Lifting state up
Lifting state up is a technique where the state is moved to a common ancestor component, enabling sibling components to share and synchronize data. This approach allows for better communication between components and promotes a unidirectional data flow.
Example: Synchronizing two input fields
function InputField(< value, onChange >) < return onChange= />; > function App() < const [value, setValue] = useState(''); function handleChange(event) < setValue(event.target.value); >return (onChange= /> onChange= />); >
✅ Compound components
Compound components are a technique to create more flexible and composable components by grouping multiple components together and managing their shared state.
Example: Customizable dropdown component
function Dropdown(< children >) < const [isOpen, setIsOpen] = useState(false); function toggleDropdown() < setIsOpen(!isOpen); >return React.Children.map(children, (child) => < return React.cloneElement(child, < isOpen, toggleDropdown >); >); > function DropdownButton(< toggleDropdown >) < return ; > function DropdownContent(< isOpen, children >) < return isOpen ? : null; > function App() < return (); > Content 1
Content 2
By understanding and incorporating these advanced data binding techniques into your React applications, you can create more complex, flexible, and scalable solutions.
Conclusion
Mastering data binding in React is essential for building efficient, maintainable, and scalable web applications. Understanding the different techniques, such as one-way data binding with state and props and two-way data binding with controlled components, will help you easily create powerful applications.
To further your knowledge, consider exploring resources like the official React documentation, online tutorials, and community-driven content. Continuously experiment with advanced techniques, libraries, and tools to expand your skill set and keep up with the ever-evolving world of web development.