Data binding in React
ReactjsReactjs Problem Overview
What I want to do is when I type some text in an input field, it should appear in another place realtime.
Below is my input;
<div className="post_input">
<input className='post_data_input_overlay' placeholder="Ask your question here" ref="postTxt"/>
</div>
How can I achieve that?
Reactjs Solutions
Solution 1 - Reactjs
Data binding in React can be achieved by using a controlled input
. A controlled input is achieved by binding the value to a state variable
and a onChange
event to change the state as the input value changes.
See the below snippet
class App extends React.Component {
constructor() {
super();
this.state = { value: 'Hello World' };
}
handleChange = (e) => {
this.setState({ value: e.target.value });
};
render() {
return (
<div>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
<p>{this.state.value}</p>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
Update: React Hooks
Here is an equivalent function component of the class defined above.
const { useState } = React;
const App = () => {
const [value, setValue] = useState('Hello World');
const handleChange = (e) => setValue(e.target.value);
return (
<div>
<input type="text" value={value} onChange={handleChange} />
<p>{value}</p>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Solution 2 - Reactjs
To be short, in React, there's no two-way data-binding.
So when you want to implement that feature, try define a state
, and write like this, listening events, update the state, and React renders for you:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} />
);
}
}
Details here https://facebook.github.io/react/docs/forms.html
UPDATE 2020
> Note: > > LinkedStateMixin is deprecated as of React v15. The recommendation is > to explicitly set the value and change handler, instead of using > LinkedStateMixin.
above update from React official site . Use below code if you are running under v15 of React else don't.
There are actually people wanting to write with two-way binding, but React does not work in that way. If you do want to write like that, you have to use an addon for React, like this:
var WithLink = React.createClass({
mixins: [LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function() {
return <input type="text" valueLink={this.linkState('message')} />;
}
});
Details here https://facebook.github.io/react/docs/two-way-binding-helpers.html
For refs
, it's just a solution that allow developers to reach the DOM in methods of a component, see here https://facebook.github.io/react/docs/refs-and-the-dom.html
Solution 3 - Reactjs
With introduction of React hooks the state management (including forms state) became very simple and, in my opinion, way more understandable and predictable comparing with magic of other frameworks. For example:
const MyComponent = () => {
const [value, setValue] = React.useState('some initial value');
return <input value={value} onChange={e => setValue(e.target.value)} />;
}
This one-way flow makes it trivial to understand how the data is updated and when rendering happens. Simple but powerful to do any complex stuff in predictable and clear way. In this case, do "two-way" form state binding.
The example uses the primitive string value. Complex state management, eg. objects, arrays, nested data, can be managed this way too, but it is easier with help of libraries, like Hookstate (Disclaimer: I am the author of this library). Here is the example of complex state management.
When a form grows, there is an issue with rendering performance: form state is changed (so rerendering is needed) on every keystroke on any form field. This issue is also addressed by Hookstate. Here is the example of the form with 5000 fields: the state is updated on every keystore and there is no performance lag at all.
Solution 4 - Reactjs
To bind a control to your state you need to call a function on the component that updates the state from the control's event handler.
Rather than have an update function for all your form fields, you could create a generic update function using ES6 computed name feature and pass it the values it needs inline from the control like this:
class LovelyForm extends React.Component {
constructor(props) {
alert("Construct");
super(props);
this.state = {
field1: "Default 1",
field2: "Default 2"
};
}
update = (name, e) => {
this.setState({ [name]: e.target.value });
}
render() {
return (
<form>
<p><input type="text" value={this.state.field1} onChange={(e) => this.update("field1", e)} />
{this.state.field1}</p>
<p><input type="text" value={this.state.field2} onChange={(e) => this.update("field2", e)} />
{this.state.field2}</p>
</form>
);
}
}
ReactDOM.render(<LovelyForm/>, document.getElementById('example'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="example"></div>
Solution 5 - Reactjs
> This could be achieved with a hook. However, I would not recommend it, as it strictly couples state and layout.
November 2019 Data Bind with Hooks
const useInput = (placeholder, initial) => {
const [value, setVal] = useState(initial)
const onChange = (e) => setVal(e.target.value)
const element = <input value={value} onChange={onChange} placeholder={placeholder}/>
return {element, value}
}
Use it in any functional component
const BensPlayGround = () => {
const name = useInput("Enter name here")
return (
<>
{name.element}
<h1>Hello {name.value}</h1>
</>
)
}
Basic version - bind value and onChange
const useDataBind = () => {
const [value, setVal] = useState("")
const onChange = (e) => setVal(e.target.value)
return {value, onChange}
}
const Demo = (props) => {
const nameProps = useDataBind()
return (
<>
<input {...nameProps} placeholder="Enter name here" />
<h1>Hello {nameProps.value}</h1>
</>
)
}
Solution 6 - Reactjs
January 2022
Using hooks you can write a custom component which does exactly what you want.
I used TypeScript in the example below:
// InputBind.tsx
import {useState} from 'react';
export interface Binder {
value: string;
setter: (value: string) => void;
}
/**
* Hook that returns a value to be used with InputBind component.
*/
export function useBind(initialValue: string): Binder {
const [value, setter] = useState(initialValue);
return {value, setter};
}
/**
* Custom input component with binding.
*/
export function InputBind({value}: {value: Binder}) {
return <input type="text" value={value.value}
onChange={e => value.setter(e.target.value)} />;
}
This is how you use it:
import {InputBind, useBind} from './InputBind';
function Foo() {
const name = useBind('john');
console.log('Value is', name.value);
return (
<div>
<div>The name is {name.value}.</div>
<InputBind value={name} />
</div>
);
}
The example above is very simple. The concept can be expanded to other input
types and select
s as well.
Solution 7 - Reactjs
With the new feature called Hooks from the React team which makes functional components to handle state changes.. your question can be solved easily
import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom';
const Demo = props =>{
const [text, setText] = useState("there");
return props.logic(text, setText);
};
const App = () => {
const [text, setText] = useState("hello");
const componentDidMount = () =>{
setText("hey");
};
useEffect(componentDidMount, []);
const logic = (word, setWord) => (
<div>
<h1>{word}</h1>
<input type="text" value={word} onChange={e => setWord(e.target.value)}></input>
<h1>{text}</h1>
<input type="text" value={text} onChange={e => setText(e.target.value)}></input>
</div>
);
return <Demo logic={logic} />;
};
ReactDOM.render(<App />,document.getElementById("root"));
Solution 8 - Reactjs
class App extends React.Component {
constructor() {
super();
this.state = {value : ''}
}
handleChange = (e) =>{
this.setState({value: e.target.value});
}
render() {
return (
<div>
<input type="text" value={this.state.value} onChange={this.handleChange}/>
<div>{this.state.value}</div>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="app"></div>
Solution 9 - Reactjs
> There are actually people wanting to write with two-way binding, but React does not work in that way.
That's true, there are people who want to write with two-way data binding. And there's nothing fundamentally wrong with React preventing them from doing so. I wouldn't recommend them to use deprecated React mixin for that, though. Because it looks so much better with some third-party packages.
import { LinkedComponent } from 'valuelink'
class Test extends LinkedComponent {
state = { a : "Hi there! I'm databinding demo!" };
render(){
// Bind all state members...
const { a } = this.linkAll();
// Then, go ahead. As easy as that.
return (
<input type="text" ...a.props />
)
}
}
The thing is that the two-way data binding is the design pattern in React. Here's my article with a 5-minute explanation on how it works
Solution 10 - Reactjs
Define state attributes. Add universal handleChange event handler. Add name param to input tag for mapping.
this.state = { stateAttrName:"" }
handleChange=(event)=>{
this.setState({[event.target.name]:event.target.value });
}
<input className="form-control" name="stateAttrName" value=
{this.state.stateAttrName} onChange={this.handleChange}/>
Solution 11 - Reactjs
Some modules makes simpler data-binding in forms, for example:
react-distributed-forms
class SomeComponent extends React.Component {
state = {
first_name: "George"
};
render() {
return (
<Form binding={this}>
<Input name="first_name" />
</Form>
);
}
}
https://www.npmjs.com/package/react-distributed-forms#data-binding
It uses React context, so you don't have to wire together input in forms
Solution 12 - Reactjs
Don't need to Break head with setState() in react.js
A new library made by me React-chopper
Code Like angularjs in reactjs
Code without setState in reactjs
Go through examples for more description
import React, { Component } from 'react';
import { render } from 'react-dom';
import Rcp from 'react-chopper';
class App extends Component {
constructor(props) {
super(props);
this.state = {
name: 'React'
};
this.modal = Rcp(this.state, this);
}
tank = () => {
console.log(this.modal)
}
render() {
return (
<div>
<input value={this.modal.name} onChange={e => this.modal.name = e.target.value} />
<p> Bang Bang {this.modal.name} </p>
<button onClick={() => this.tank()}>console</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Comments , Pr Are welcome ...Enjoy
Solution 13 - Reactjs
I think @Richard Garside is correct.
I suggest some changes to clear even more the code.
Change this
onChange={(e) => this.update("field2", e)}
To this
onChange={this.handleOnChange}
And also, change this
this.setState({ [name]: e.target.value });
To this
this.setState({ [e.target.name]: e.target.value})
Besides, you have to add the "name" attribute to the field with a value that relates with the key on the state object.