I just wonder if it is good that the child component updates the parent component.
in the source code, like following
class Parent extends React.Component{
state = {
name : ''
}
changeState = ((state) => {
this.setState(state)
})
submit = (() => {
// send state to api..
})
render(){
return(
<div>
<Child changeState={this.changeState} {...this.state}/>
<button onClick={this.submit} />
</div>
)
}
}
class Child extends React.Component{
change = ((e) => {
this.props.changeState({
name : e.target.value
})
})
render(){
return(
<input onChange={this.change} value={this.props.name} />
)
}
}
the reason I use this way is submitting method.
There are many input tags, and I want to bind them all together.
but I'm not sure this way is good or not.
because when I type something, parent component always will rerender.
I think it is not good.(actually it just my thinking...)
is it right?
I have used this way to update state of a parent from a child. It does work properly. But it makes the components little complex.
In your case (assuming you do this for text input elements) I don't think this will be a good practice if you are doing it for tiny input components. Because every time you hit a key on a keyboard the parent component will try to update.
But if you are wrapping a set of input elements and pass a larger object to a parent component I think that will be fine.
You could use react life cycle method shouldComponentUpdate() method to control the rendering of the parent component
shouldComponentUpdate
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
shouldComponentUpdate(nextProps, nextState) {
if (this.props.name != nextProps.name) {
return true;
} else {
return false;
}
}
Here nextProps refers to the props you receive(updates) and you can refer to current prop values by "this.props"
And return true to render and false to skip the rendering.
If you have perform validations when the user inputs, then its ok.
Otherwise change 'onChange' event to 'onBlur'
Its a good idea to lift the state up and update it in the parent if multiple other siblings want to refer to the same values. You can optimise on this my making your Parent and Child Components pure as long as they don't have complex and deeply nested props and states.
According to the React docs:
React.PureComponent is exactly like React.Component, but
implements shouldComponentUpdate() with a shallow prop and state
comparison. If your React component’s render() function renders the
same result given the same props and state, you can use
React.PureComponent for a performance boost in some cases.
Re-rendering of parent is not a problem as long as it is not wasted. And Unless you are using Redux, I think this is a proper way to manage the state, i.e., inside the parent component and updating it using the child. In this way, you have made your form into a controlled component.
I think the following page will be useful to you: https://scotch.io/courses/getting-started-with-react/parent-child-component-communication
Related
I'm learning React. I learned that props in react are readonly.
But i read somewhere:
getDerivedStateFromProps updates the state based on prop changes
So i got confused. If props are readonly, how they can change?
They are readonly in the context of a component, meaning, you can't assign a new value to them.
But a parent that passes props to child, can pass different props based on some condition. In that case, the child get rendered with a different props.
Example:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
};
}
render() {
return (
<div>
<Child prop1={this.state.value} />
<button onClick={() => this.setState({ value: this.state.value + 1 })}>Click me</button>
</div>
);
}
}
In my example, each click on the parent's button will change it state, therefore, React will re-render it, and then this parent will pass a new value to Child component.
I think you need to understand component life-cycle and how to use and handle props which is described beautifully in below links:
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
https://reactjs.org/docs/components-and-props.html#props-are-read-only
Props are read only means you can't change the value, but it doesn't mean you can't update it, for that you need to pass updated props back to child component and go any lifecycle methods to it.
An update can be caused by changes to props or state.
when there is update render() method is get called.
you are saying update to props, which directly means you are changing and modifying child,
props changed means, the data passed from parent is changed which leads in changing props,
always remember state passed from parent is considered as props for child is key point.
static getDerivedStateFromProps(props, state) gets called right after render() used rarely mailnly for animations transitions purposes.
the things possible with componentWillRecieveProps() and componentDidUpdate() is now done by getDerivedStateFromProps(), it will return object in response to change in props, and null if no change, sounds wonderful.
as you can see method is static you cant change any data, you can just play with your nextProps and prevState only.
this is useful for components having async api calls.
I am working since more than a year with React and i have read Thinking in react, Lifting state up, and State and lifecycle.
I have learned that React's concept with data flow is is One-way data flow.
Citates from these pages:
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:...
If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.
As i understand this, following example is not allowed because i am passing child state data to the parent. But i see some developers working like that:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { fromParent: null };
}
addSomething(stateValueFromChild) {
this.setState({fromParent: stateValueFromChild});
}
render() {
return <Child
addSomething={(stateValueFromChild) => this.addSomething(stateValueFromChild)}>
// ...
</Child>;
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = { fromChild: 'foo' };
}
render() {
return <Form onSubmit={() => this.props.addSomething(this.state.fromChild)}>
// ...
</Form>;
}
}
My questions now are:
Is this really not allowed?
Why should this not be modular and fast?
Is this really braking the one-way-dataflow, becoming a two way dataflow?
What other problems could happen with this way?
When i would lift the state up, how would you solve following case; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using?
Is this really not allowed?
Why should this not be modular and fast?
Excellent questions. This is allowed. It's just a bit tricky to make it work right because you've got state synchronization here. In the modern frontend world, the state synchronization is believed to be a very challenging task.
The problem will appear when you'll need to sync the state in two directions. For instance, if this child form is used to edit some element of the list, and you're changing the current element of the list. You'll need the child component to detect that situation and sync its local state with the new element from props during the particular UI update. As long as you don't have that, you're fine.
Is this really braking the one-way-dataflow, becoming a two way dataflow?
Nah, it's not. It's still unidirectional data flow because React can't work in any other way by design; UI updates always coming from top to bottom. In your example, your child triggers an event which causes the parent to update its state (it's totally fine), which will cause the UI update of the parent and the child. If you really violate "unidirectional data flow", you'll feel it. You will get an infinite loop or something similar.
When i would lift the state up, how would you solve following case; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using?
Yep, that's what they mean by "lifting the state". You organize your root state as a tree reflecting the state of the children, then pass down elements of the state to children along with callbacks to modify the root state.
It's allowed and there is nothing wrong with your code, but I would not call it passing state from child to parent. All you do is invoking method passed in props and triggered by event with some argument, which in your example is child's state value, but it could be any other variable. Parent component knows nothing about nature of this argument, it just receives the value and able to do anything with it, for example change it's own state to another. If Child's state will change, Parent is not going to receive this update without onSubmit event fired again. But children always receive updates from the parent and automatically get rerendered, when props get changed. And of course some of the props could be states of some parents. Here is the major difference in behavior.
There is a good article explaining this in details: Props down, Events Up
Your question is absolutely correct, many times developer (including myself) struggled for passing child's components state or props to parent component.
I always do logic for getting next state or next props in child component and pass next state or next props to parent component by using handler functions of parent component.
import React, { Component } from "react";
import { render } from "react-dom";
class Parent extends Component {
constructor(props) {
super(props);
this.handleSomething = this.handleSomething.bind(this); // binding method
this.state = {
fromParent: "foo"
};
}
handleSomething(value) {
this.setState(prevState => {
return {
fromParent: value
};
});
}
render() {
return (
<div>
<h1>State: {this.state.fromParent}</h1>
<Child handleSomething={this.handleSomething} />
</div>
);
}
}
class Child extends Component {
constructor(props) {
super(props);
this.state = {
fromChild: "bar"
};
}
render() {
return (
<div>
<button
onClick={e => {
const { fromChild } = this.state;
// do whatever as per your logic for get value from child pass to handleSomething function
// you can also do same for handling forms
this.props.handleSomething(fromChild);
}}
>
Click Me
</button>
</div>
);
}
}
render(<Parent />, document.getElementById("app"));
I'm a bit new to React, so forgive me if this is a bit of a newb question.
I have a base component (Page) which uses state to control whether or not a modal popup is displayed:
constructor(props) {
super(props);
this.state = {
showModal : false,
modalContent : 'Initial Modal Content'
};
this.showModal = this.showModal.bind(this);
this.hideModal = this.hideModal.bind(this);
}
showModal(modalContent) {
this.setState({
showModal : true,
modalContent : modalContent
});
}
hideModal(e) {
this.setState({showModal : false});
}
My problem is that I want a grandchild component to be able to open up my modal.
I know I can do this by passing the state to the child component and then to the grandchild component:
<PartnersTable showModal={this.showModal} partners={PARTNERS} />
That just seems a bit sloppy to me, but maybe that's just the React way.
Can someone let me know if I'm doing this properly or if there's a cleaner way to do this?
You can view my full app on GitHub: https://github.com/CCChapel/Thy-Kingdom-Come/blob/master/react.js
Thanks!
-Eric
You're doing it correctly.
In React the only way for a parent to pass props/state to it's children is by passing it downwards. React is unidirectional from top to bottom; from parent to child only.
So your assumption is correct. It can get pretty sloppy. You must know that React is for presenting the UI and simple cases of state management. When you're application gets more complex and you need to pass down state in a direct and simplified manner use Redux, MobX or any other state containers out there.
If you don't like the complexity of passing down props down the tree considering using Redux (I use Redux myself).
Consider the following resources:
https://egghead.io/courses/getting-started-with-redux
http://redux.js.org/docs/introduction/
https://github.com/reactjs/redux/tree/master/examples
To learn how React works though get used to using only React first then use a state container when the application gets more complex.
In order to achieve that you need to pass your showModal method as a prop to child component(s) in which you want to trigger the visibility of the modal. This is how the render method of the parent component should be:
render() {
return(
<ChildComponent showModal={this.showModal}>
)
}
Then in you child component:
class ChildComponent extends Component {
render() {
return(
<input type="button" onClick={this.props.showModal} value="show modal"/>
)
}
}
I am using two components and I am using this pattern: child component should stay isolated as much it can - it is handling its own validation error. Parent component should check for errors which have dependencies between children. So, in my case: password field and password confirmation field.
Here is my code:
a) SignUp (parent)
Setting initial state.
constructor() {
super();
this.state = {
isPasswordMatching: false
};
}
In render() method I am outputting my child component. Through prop called callback I am propagating method isPasswordMatching() by binding parent's this. The goal is that method can be called within child component.
<TextInput
id={'password'}
ref={(ref) => this.password = ref}
callback={this.isPasswordMatching.bind(this)}
// some other unimportant props
/>
<TextInput
id={'passwordConfirm'}
ref={(ref) => this.passwordConfirm = ref}
...
isPasswordMatching() method is checking if passwords match (through refs this.password and this.passwordConfirm) and then updates state. Please note that this method is called inside child (password or passwordConfirm).
isPasswordMatching() {
this.setState({
isPasswordMatching: this.password.state.value === this.passwordConfirm.state.value
});
}
b) TextInput (child)
Setting initial state.
constructor() {
super();
this.state = {
value: '',
isValid: false
};
}
On blur validation is done and state is updated.
onBlur(event) {
// doing validation and preparing error messages
this.setState({
value: value,
isValid: this.error === null
});
}
Latest. Callback prop is called.
componentDidUpdate(prevProps) {
if (prevProps.id === 'password' || prevProps.id === 'passwordConfirm') {
prevProps.callback();
}
}
Issue
Somehow my refs are lost. Scenario:
Parent component is renderder
Child components are rendered
I am entering one of input fields and get out (this invokes onBlur() method) - state gets updated, child component is rendered
componentDidUpdate() is invoked and prevProp.callback() as well
When going to isPasswordMatching() method I am outputting this.password and this.passwordConfirm - they are objects with expected values of reference. Updating state of parent - component gets rendered.
Then again all children are rendered, components get updated, callback is called but this time this.password and this.passwordConfirm are null.
I have no idea why references are kinda lost. Should I be doing something differently?
Thank you in advance.
See the react documentation here, with important warnings and advise about when to use or not to use refs.
Note that when the referenced component is unmounted and whenever the ref changes, the old ref will be called with null as an argument. This prevents memory leaks in the case that the instance is stored, as in the second example. Also note that when writing refs with inline function expressions as in the examples here, React sees a different function object each time so on every update, ref will be called with null immediately before it's called with the component instance.
I'm not sure if this answers #be-codified's question for not, but I found this running into a similar issue. In my case, it turned out that it was due to using a functional component.
https://reactjs.org/docs/refs-and-the-dom.html#refs-and-functional-components
Refs and Functional Components
You may not use the ref attribute on functional components because they don’t
You should convert the component to a class if you need a ref to it, just like you do when you need lifecycle methods or state.
You can, however, use the ref attribute inside a functional component as long as you refer to a DOM element or a class component
The documentation explains what you should do to solve the issue if you have control of the component you're trying to render.
However in my case, the component was from a 3rd party library. So, simply wrapping the component worked fine.
Working
<div ref={element => this.elementName = element}>
<FunctionalComponent />
</div>
Not Working
sets this.elementName to null
<FunctionalComponent ref={element => this.elementName = element} />
Hope this helps anyone finding this question like I did.
I've been using React for a while, and I've tried many different approaches to do this, they all have their advantages and disadvantages so I'd like to clarify which one is the way to go.
So I have this example scenario:
- A (smart) parent component, listening to a flux store
- A (dumb?) child component being rendered by the parent component above only rendering a view and having some "small internal logic", and by that I mean, some logic that doesn't make sense to be handled by an external action, like onChange events that update its input value, for example.
Should I only pass whatever I wanna pass to the child component as props, and don't mess with its state. So whatever small logic I need to do I update its props directly (even tho I know it's not recommended to update props directly)?
Or
I pass whatever props I wanna pass to the child component and then "get them" in the getInitialState, do that small logic using its now state variables?
The problem with the second approach is that when I actually send an action from the child component, and the parent component listens to the stores results and gets updated, and I have a hard time re rendering the child component now, unless I change its key value, which I also think it shouldn't be done this way.
And the first approach, even tho I'm changing props, which, like I said, I don't think it's also the best thing to do this, I don't have a problem re rendering the child component after sending an action that updates the store that the parent component is listening to.
Probably there are other ways to do it, and for sure a better way. And that is what I'd like to see. Let me know if the question is confusing and I'll try explaining in some other way.
Thanks!
You should only set state from the main (parent) component. All children components should be "dumb" components. If you need to manipulate state from a child component...have a function in the parent component that modifies the state needed...then pass that function as a prop to the child. When the action needed to update the state in the child is completed, call the function passed in as a prop which will call it in the parent component and will update state accordingly.
Below is just some boilerplate code to give you an idea as to what I'm talking about.
Example child component:
import React, {Component} from 'react';
class Child extends Component {
edit = () => {
var state = "string";
this.props.edit(state);
}
handleChange = (evt) => {
this.props.inputChange(evt.target.value);
render() {
return (
<button type="button" onClick={this.props.edit}>Click Me!</button>
<input type="text" name="name" onChange={this.handleChange}>
)
}
}
export default Child;
Example parent component :
import React, {Component} from 'react';
import Child from './Child';
class Parent extends Component {
edit = (val) => {
this.setState({data: val})
}
inputChange = (val) => {
this.setState ({input: val});
}
render() {
return (
<Child edit={this.edit} inputChange={this.inputChange}>
)
}
}
export default Parent;