How to update the state of a sibling component from another sibling or imported component in REACT
You need to lift your state up in your situation. The second option is what @Gavin Thomas suggested in the comment. But without Redux you can do it like:
const InputArea = (props) => {
const handleChange = (e) => props.handleInputValue(e.target.value);
return (
<div className="column">
<div className="col-body">
<textarea
id="editor"
placeholder="Enter text here"
onChange={handleChange}
></textarea>
</div>
</div>
);
};
const DisplayArea = (props) => (
<div className="column">
<div className="col-body">
<div id="preview">{props.inputValue}</div>
</div>
</div>
);
class App extends React.Component {
state = {
inputValue: "Initial Value",
};
handleInputValue = (inputValue) => this.setState({ inputValue });
render() {
return (
<div id="wrapper" className="App">
<DisplayArea inputValue={this.state.inputValue} />
<InputArea handleInputValue={this.handleInputValue} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
<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="app"></div>
Here, we hold our input value state in the parent component, which is App. We pass a callback function to InputArea and change our parent component's state using this callback function. Then we pass this state to our DisplayArea component.
Here are the relevant parts of the code. Basically passing a liftState
method to the InputArea
component which will actually update the state of App
when called. Then pass content
to DisplayArea
as a prop.
class App extends Component {
constructor(props) {
super(props);
this.state = {
content: ""
};
}
liftState = state => {
this.setState(state);
}
render() {
return (
<div className="App">
<InputArea liftState={this.liftState}/>
<DisplayArea content={this.state.content}/>
</div>
);
}
}
class InputArea extends Component {
handleChange(event) {
this.props.liftState({content: event.target.value});
}
}
class DisplayArea extends Component {
render() {
return (
<div className="column">
<div className="col-body">
<div id="preview">{this.props.content}</div>
</div>
</div>
)
}
}
The React.js documentation says (Lifting State Up):
Often, several components need to reflect the same changing data. We recommend lifting the shared state up to their closest common ancestor...
Example:
// Parent component which contains shared state
class Parent extends Component {
constructor(props) {
super(props);
this.state = {
child1Value: 0,
child2Value: 0,
}
this.handleChild1Click = this.handleChild1Click.bind(this);
this.handleChild2Click = this.handleChild2Click.bind(this);
}
handleChild1Click(nextValue) {
this.setState({ child1Value: nextValue });
}
handleChild2Click(nextValue) {
this.setState({ child2Value: nextValue });
}
render() {
return (
<div>
<Child
value={this.state.child2Value}
onClick={this.handleChild1Click}
/>
<Child
value={this.state.child1Value}
onClick={this.handleChild2Click}
/>
</div>
)
}
}
class Child extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onClick(this.props.value + 1);
}
render() {
return (
<div>
<p>Value of my sibling: {this.props.value}</p>
<button onClick={this.onClick}></button>
</div>
)
}
}