Reputation: 195
How to pass child's state back to the container? I have a very simple app but because I split them into smaller component now I'm stuck passing state value (Form) back to its container. I can also call the api in child's component then recieve it via props container but that's not clean, I want the 'final event' be placed in the container, and the container has the 'main' state.
Is my first intention (make sure 'main' state is store in the container) correct? If yes how to pass back the state from child component back to the container? Assume I'm not using redux.
https://codesandbox.io/s/8zrjjz3yjj
Upvotes: 4
Views: 971
Reputation: 31024
You should lift the state up.
Let a parent component deal with a state that concern its children, and pass handlers to the children so the children can invoke them and pass them back the relevant values.
Here is a running example of this approach with your code:
class AddUser extends React.Component {
onChange = ({ target }) => {
const { onChange } = this.props;
onChange(target.value);
}
render() {
return (
<div>
<input onChange={this.onChange}
type='text' placeholder='user' />
</div>
)
}
}
class Modal extends React.Component {
state = { newUser: '' }
onUserChange = newUser => this.setState({ newUser });
addUser = () => {
const { addUser } = this.props;
const { newUser } = this.state;
addUser(newUser);
this.setState({ newUser: '' }); // reset the field
}
render() {
return (
<div>
<AddUser onChange={this.onUserChange} />
<button onClick={this.addUser}>add</button>
</div>
)
}
}
class MainContainer extends React.Component {
state = {
showAddUser: false,
users: [{
name: 'Jane'
}, {
name: 'Black'
}]
}
addUserIntoUsers = (userName) => {
const { users } = this.state;
if (userName) { // only if we have a value
const nextUsers = [...users, { name: userName }];
this.setState({ users: nextUsers, showAddUser: false });
}
}
render() {
return (
<div>
<button onClick={() => this.setState({ showAddUser: !this.state.showAddUser })}>
Toggle User Panel
</button>
<br />
{this.state.users.map(o => {
return (<div>{o.name}<br /></div>)
})}
{this.state.showAddUser && <Modal addUser={this.addUserIntoUsers} />}
</div>
)
}
}
ReactDOM.render(<MainContainer />, document.getElementById('root'));
<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="root"></div>
Upvotes: 1
Reputation: 10738
Pass a method as props:
Parent:
class Parent extends Component {
....
render = () => <Child onChange={childDidSomething}/>
childDidSomething = state => {
...
}
}
Child:
class Child extends Component {
....
render() {...}
somethingChanged() {
this.props.onChange(this.state);
}
}
Upvotes: 4