Formik and ReactJs : SetFieldValue from child to parent component - javascript

I am Working on a ReactJs project and I use formik in it.
I have 2 different components (parent and child).
Here is the example, I tried to pass the formik data from parent to child and I need to set parent formik values from child component.
Right now I face an error as my parent component call child and when the child updates parent value it will again call the child and goes in the infinite loop.
Parent.js
<GSTData gstData={this.props.gstDetails?.GstDetails}
amount={this.props.totalAmount}
onInputControlChange={(Total, GstData) => {
TotalBillAmount = Total;
GstDetails = GstData;
console.log('Total', TotalBillAmount)
//setFieldValue('NetOutStanding', 1);
}}
values={values}
setFieldValue={setFieldValue}
/>
Child.js
componentDidUpdate(){
this.props.onInputControlChange((this.GSTTotal + this.props.amount), this.GstDetails);
this.props.setFieldValue('NetOutStanding', (this.GSTTotal + this.props.amount));
}

What's happening is that when you update the input it calls the parent with the value to set. The parent then passes that value back to the child as a prop, which the Child perceives as an update, which then tells the parent the value again..... thus infinite loop
I would try taking
this.props.setFieldValue('NetOutStanding', (this.GSTTotal + this.props.amount));
out of the componentDidUpdate in the child component and calling it from it's own function.(This means you'll also have to set the value of the input being passed in from the parent directly). That should break the cycle

Related

prevent rerendering of some component inside array in react

Suppose, i have a component Parent and i am rendering children like this.
const [items,setItems] = useState([1,2,3,4,5,6....]);
const [pointer,setPointer] = useState(0);
// inside return
{items.map((item,idx)=>{
return <ChildCanvas text={item} isPointer={pointer===idx} key={idx} idx={idx}/>
})}
pointer and items both are different states in the same component. Whenever pointer changes I am doing some animation inside that child(pointer===idx).
At a time, isPointer will be true for only one ChildCanvas component. Here I am expecting that, react will rerender the child whose isPointer props has been changed.
But, here whenever isPointer changes, React is rerendering all ChildCanvas components. ChildCanvas is a heavy component, so this makes the page (unresponsive for some time).
How i checked if a particular ChildCanvas has been rerendered or not.
function ChildCanvas({text,isPointer,idx}){
console.log(`child ${idx} has been rerendered`);
return // code...
}
Now, whenever pointer changes then i am getting this
child 0 has been rerendered
child 1 has been rerendered
child 1 has been rerendered
// up to the length of the array
How can i make sure to rerender only the component whose isPointer props has been changed.

How can I prevent rerendering of a pure component with pure children in React?

I have a functional React component in which I use React.memo to prevent unnecessary rerenders. If it contains only a string as a child, it is only rendered only when the string is changed (as expected). However, When I add another child component which also uses React.memo, it is always rerendered (even when child component is not rerendered). Here is a sample code indicating those cases:
const Parent = React.memo(() => <div> Parent </div>) // Rendered only once!
Second Case:
const Child = React.memo(() => <div> Child </div>); // Rendered only once!
const Parent = React.memo(() => <Child />); // Rerendered everytime
To be more clear, the Parent is always rerendered (as if React.memo is not used) in the second case. Obviously, there is no need to rerender it as its child does not rerender and thus none of Parent's children is changed. Is there something I am missing? How can I change my implementation to avoid rerendering of Parent component?

Can't use state value as props for child component

In my react js app, I can't seem to use the state value as props for the child component.
In the parent component, constructor, the app has a null state called selectedWarehouseID.
This state(selectedWarehouseID) should update with some information in the componentWillMount() method.
Now, in the render method of the parent component I am embedding another child component that has this state as a props.
<ItemChooser
productsByWarehouse = { this.state.selectedWarehouseID }
/>
Now here's the problem, in the child component, the value of this.props.productsByWarehouse is always null. I found a nice explanation of why this happens, but how to wait for the data that updates in the parents componentWillMount() to access the updated value of the state that being passed in the child component props?
Possible solutions are:
1. You are storing the props value in state of child component so, Update the state of child component whenever any change happen to props values (state of parent). For that use componentWillReceiveProps lifecycle method.
componentWillReceiveProps():
is invoked before a mounted component receives new props. If you need
to update the state in response to prop changes (for example, to reset
it), you may compare this.props and nextProps and perform state
transitions using this.setState() in this method.
Like this:
componentWillReceiveProps(newProps){
this.setState({
value: newProps.productsByWarehouse
});
}
Note: Replace value by the actual key in which you are storing the value.
2. Don't store the props values in state of child component, directly use this.props.productsByWarehouse, Whenever you change the parent state values, child will automatically get the updated value in props.

calling and pass arguments to children component's function from parent component in reactjs

I found out that my argument passed from parent to child component through refs is either undefined or an actual event instead of what I passed in.
What is the right way to actually pass argument from parent to child component's function? I am using refs but seems its not really passing anything in term of function argument.
I show the case here:
https://codepen.io/adamchenwei/pen/gLMaPo/?editors=0010
Basically if you see the line where I wrote console.log('child argument should be string'); it should be an argument actually passed instead of an event.
I wonder if I did things wrong.
For this scenario, I NEED to evaluate event in parent component and decide how I want to run the child function, with specific arguments passed in accordingly.
There are only two way to access parent props in child component. you can achieve this in following two ways:-
Pass values into child component from parent via props
Set values in state and dispatch action from child to fetch values from state.
Instead of using ref, I would use state and props:
parentDoThing(event) {
const lifeTerms = {
heaven: 'yeeeeey',
hell: 'nooooooo',
}
if(event) {
this.setState({ lifeTerms: heaven });
} else {
this.setState({ lifeTerms: hell});
}
}
render() {
return (
<section className="parent-comp"
onClick={this.parentDoThings}>
<ChildComponent
lifeTerms={this.state.lifeTerms}/>
<h1> Whats in App {this.state.text}</h1>
</section>
);}
And on child component:
render() {
return (
<section className="child">
<section>this life is {this.state.life} </section>
<button onClick={this.doChildThings.bind(this, this.props.lifeTerms)}> Button </button>
</section>
);
Resolved my issue by using componentWillUpdate in combine with using parent level state passed into child as props to trigger event inside the child, because I do not want any trigger inside the child to trigger the change provided by the parent.

Does React rerenders component when a prop is changed

Suppose I have two components named Parent and Child. In Parent component I have a state named lastName which is passed to Child as a prop. Now after initial rendering of Child and Parent, if the lastName in Parent changed, will it cause Child component to rerender?
Yes, if you set the property via setState. However, re-render in React isn't something you should be afraid of, it's very efficient due to Virtual DOM usage.
In the child component you should use the following
shouldComponentUpdate(nextProps){
return this.props.lastname !== nextProps.lastname
}
https://facebook.github.io/react/docs/component-specs.html#shouldComponentUpdate
After that, in the child component you might need to update the state. To achieve that you can use componentWillReceiveProps(nextProps)
componentWillReceiveProps(nextProps){
this.setState({
lastname: nextProps.lastname
});
}
The Child component is only re-rendered when props lastName is being used in Child's render function and Parent use setState function to change lastName. Remember, React is one-way dataflow, if you want to re-render Child component right inside the Child, you must call an event which also trigger setState back to Parent component

Categories