How the componentWillReceiveProps update the props in react? - reactjs

Below is some code snippets for the componentWillReceiveProps.
Here bulkUploadRptSuccess, bulkUploadRptError are the array and bulkUploadRptException is the string.
so once state updating two array and one string it is opening the popup.
its working as expected.
But now when clicking on any thing into the application open the pop up everytime.
How can I compare the conditional array check inside the componentWillReceiveProps.
How can I compare the two array value with the equal or not inside this function
Thanks,
componentWillReceiveProps = (nextProps) => {
let { OCFCheckConfig } = this.props;
let { bulkUploadRptSuccess, bulkUploadRptError, bulkUploadRptException } = OCFCheckConfig;
if (nextProps.OCFCheckConfig.bulkUploadRptSuccess.length > 0 || nextProps.OCFCheckConfig.bulkUploadRptError.length > 0) {
this.addPopupOpen();
}
}

ComponentWillReceiveProps doesn't update props. It actually receives updated props when parent re-render or you're connected to redux and your store gets updated. Anyways It is unsafe to use ComponentWillReceiveProps. Now here we have a replacement for it, getDerivedStateFromProps.

Related

When does state update in React

I am just learning React and I was doing the tutorial : https://reactjs.org/tutorial/tutorial.html
In it, we are suppose to create a function that calculate the winner of the tic-tac-toe and we pass to it the list of the squares' contents. I update this list each time a square is clicked. However, I noticed that when I use this.setState to set the squares list of my Board object and then try to have it with this.state.squares I do not get the active state but the previous one.
Like if I add an X in the first square, it will be in this.state.squares at the next move.
Here is the code, I use :
handleClick(square){
let squares = this.state.squares.slice();
squares[square] = this.state.playing;
console.log(squares);
this.setState({squares: squares});
if(this.state.playing == 'X'){
this.state.playing = 'O';
}
else{
this.state.playing = 'X';
}
this.state.winner = calculateWinner(this.state.squares); #If I do that I get the previous state
this.state.winner = calculateWinner(squares); #If I do that I get the current state
}
Why does it do that ?
According to the docs:
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
setState is an asynchronous method which effectively means that all other code in your handleClick function will execute before this.state.squares is mutated.
But there's another issue in your code too -- you're also trying to modify state directly:
if(this.state.playing == 'X'){
this.state.playing = 'O';
}
else{
this.state.playing = 'X';
Modifying this.state directly will not re-render your component.
To resolve these issues, you may use a setState callback:
this.setState({squares: squares}, () => {
if(this.state.playing == 'X'){
this.setState({"playing":"O"});
}
else{
this.setState({"playing":"X"});
}
// I'm assuming that `calculateWinner` does not depend on this.state.playing
this.setState({"winner":calculateWinner(this.state.squares));
});
The setState callback is only invoked once the this.state.squares mutation has occurred -- ensuring that this.state.squares is updated before you invoke calculateWinner.
setState is asynchronous but it can take a callback:
this.setState(
{ squares: squares },
() => console.log("whatever")
);
Heres a quick walkthrough of the different methods of the
LifeCycle
of a component.
You must have good understanding of the lifecylce methods to code in react.
It will tell you "
When does state update in React
"
Methods in Mounting Phase:
It begins when an instance of a component is created and when it gets rendered into the DOM.
1.constructor(props) - it is called when the component is first initialized. This method is only called once.
2.componentWillMount() - it is called when a component is about to mount.
3.render() -it is called when a component is rendered.
4.componentDidMount() - it is called when a component has finished mounting.
Methods in Updating Phase:
It begins when a component's properties or state changes.
1.componentWillReceiveProps(nextProps) - it is called when a component has updated and is receiving new props.
2.shouldComponentUpdate(nextProps, nextState) -it is called after receiving props and is about to update. If this method returns false, componentWillUpdate(), render(), and componentDidUpdate() will not execute.
3.componentWillUpdate(nextProps, nextState) -it is called when a component is about to be updated.
4.render() - called when a component is rerendered.
5.componentDidUpdate(prevProps, prevState) -it is called when a component has finished updating.
Methods in Unmounting Phase:
It begins when a component is being removed from the DOM.
1.componentWillUnmount() - it iscalled immediately before a component unmounts.

React Component state value not updated, when setState is called on jsonObject's property

I am working on three properties of JSON object which returns boolean values.
updateChange=(value) =>{
//Making copy of existing json Object
let newState = JSON.parse(JSON.stringify(this.state.mainValue));
// chaning property of cellular over here
newState.cellular = value;
console.log(newState);
this.setState({mainValue:newState});
//I tried setState in many different ways. But Component is not changing state value
console.log(this.state.mainValue)
};
I found why this is happening. I am using getDerivedStateFromProps in this component to look at changes made by parent to update values. This is avoiding changes made to state of the child. So I have created a state called previous state to compare the previous props and present props from parent to render. This avoids component to refresh when ever it local state values changes.
static getDerivedStateFromProps(propsnow,state){
if(state.previous !== propsnow.detailSwitches){
return{
previous :propsnow.detailSwitches,
cellular: propsnow.detailSwitches.cellular,
wifi1: propsnow.detailSwitches.wifi1,
wifi2: propsnow.detailSwitches.wifi2
};
}
return null;
}
Any examples or better practices can be helpful. Thanks
You are ONLY setting the 'mainValue' variable of your state to the value of newstate, shouldn't you be updating the whole state?
this.setState({...newState})
You can try this
this.setState(prevState => ({
mainValue: {
...prevState.mainValue,
cellular: value
}}))
It is an immutable way to update state.

Reactjs, is setState needed here, changing value of an object in state

My question is, is it ok to not use setState in this situation or if I should, how would I go about it?
I'm creating a sportsbetting app.
On the list of games, when a user clicks on Denver Broncos -3, a bet slip is created. This also calls
setState({gameSelected:[item]}) in the Parent Component.
It stores that object and adds to it using the spread operator when more bets are clicked.
I pass down that data to betSlip.js file.
side note
Some of the data in the gameSelected object has :
risk:'',
win:'',
On betSlip.js I am looping through that data and displaying it.
Relevant code inside the loop.
<input type="text" placeholder="Risk" onChange={(e)=>this.handleBet(e,item)}/>
<input type="text" placeholder="Win" value={item.win}/>
This function is inside betSlip.js
handleBet = (e,item) =>{
let bet=e.target.value
//function to calculate moneyline bet
let calcBet =(bet)=>{
let newAmount =(100/item.juice)*bet;
return newAmount
}
item.win = calcBet(bet)
}
Yes, you should be using setState here to update item.win. Otherwise, React is not aware of the mutation on item and does not rerender. Since item is a prop, you should treat it as immutable from within betSlip.js and update item.win through an event handler in the parent component where item is maintained. Your betSlip.js component could have an onWinUpdate handler that is called within handleBet as this.props.onWinUpdate(item, calcBet(bet)). Then, the parent component can have a function handleWinUpdate(item, bet) that updates the state. I would also keep things immutable in handleWinUpdate by doing something like this:
handleWinUpdate(item, bet) {
this.setState(state => ({
gameSelected: state.gameSelected.map(i => {
if (i === item) {
return { ...i, win: bet };
} else {
return i;
}
})
}));
}
Notice that we are setting gameSelected to a new array and replacing item in that array with a new copy of item, but with a new win value. No objects are ever mutated.
Even though you don't have to use immutability here, I find it easier to reason about and it opens the door for performance gains later using things like React.PureComponent that rely on immutability.

Component not updating on stateChange

I would like the value of a TextField to be some computed value... as such, I have a controlled form, ComputedValue, with a render method that looks like this:
render() {
return <TextField
value={this.state.value}
key={this.props.id}
id={this.props.id}
label={this.props.label}
inputProps={{
readOnly: true
}}
/>;
}
the ComputedValue's state.value is set by pulling data from localStorage, doing some computation, and setting the state. That method looks like this:
computeValue() {
let computedValue="";
// split the computation string into constituent components
let splitCS = this.props.computationString.split(/([+,-,*,/,(,),^])/g);
// replace all instaces of questionID's with their value
for (let i = 0; i < splitCS.length; i++) {
if (splitCS[i] !== '+' && splitCS[i] !== '-' && splitCS[i] !== '*' && splitCS[i] !== '/' &&
splitCS[i] !== '(' && splitCS[i] !== ')' && splitCS[i] !=='^') {
// splitCS[i] is a questionID
let Q = getQuestionDataFromLSbyQuestionID(splitCS[i]);
splitCS[i] = Q.value;
}
}
// check that all values returned
if(splitCS.includes("")) {
console.log("null value was returned in ComputedValue question");
} else {
// rejoin string and send to eval (TODO: replace eval)
let finalComputeString = splitCS.join('')
computedValue = eval(finalComputeString);
}
// save value in state
this.setState({
value: computedValue
}, () => {
this.props.stateChangeHandler(this);
this.render();
}
);
return computedValue;
}
This component is leaf in a tree of questions; as their values change (my app syncs LS and the head parent's state) I'd like the computed value to change.
Here are my two issues:
1) Given I call setState inside the computeValue function... I'm unable to call it from within the render function. However, if I only call it from the componentWillMount lifecycle function, it computeValue only gets called once (upon mounting) and then not again. If I call it from the componentWillUpdate, I get an infinite loop. I can put a stop in this loop by comparing nextStates and what not... but that doesn't seem like the best way.
2) renders are not triggered by an update of the parent's state.. including trying a 'forceUpdate') (though they do appear to be triggered by hovering over the mouse and various other UI things).
Given I call setState inside the computeValue function... I'm unable
to call it from within the render function.
I would like you to elaborate or clarify this statment.
However, if I only call it from the componentWillMount lifecycle
function, it computeValue only gets called once (upon mounting) and
then not again.
Yes componentWillMount is a lifecycle hook that is called only once when the component is going to be added in the tree.
If I call it from the componentWillUpdate, I get an infinite loop.
This lifecycle hook is called before your component gets updated. So if you set your state here it will again call this function and it will make a infinite loop.
I can put a stop in this loop by comparing nextStates and what not...
but that doesn't seem like the best way.
You can always do the comparing and update the state. There is nothing like a wrong way in doing so.
renders are not triggered by an update of the parent's state..
including trying a 'forceUpdate')
You should never call render explicitly. It is not a correct practice because it hinders normal flow the react.
I would like you to test the setstate
this.setState(() => ({
value: computedValue
}), () => {
console.log("working")
this.props.stateChangeHandler(this);
}
);
The problem seems to be the () in ({ value: computedValue }). Give a try.
I think your answer is in your second observation. [renders are not triggered by an update of the parent's state]. guess what triggers render from the Parent? props
so, instead of putting your value in the state, put it in the prop, that way if the parent changes it, your component changes.
Hope this helps

declaring jsx element as a global variable

Hello is there a way to declare react component globally so that when I render the same component the values are persisted, I am aware the redux or some other state management lib can be used, but for the time being I want to use this option cuz I'm in the middle of the project. For example
constructor() {
this.accountInfoJSX = <AccountInformation ref={(sender) => {
this.accountInformationMod = sender;
}} />;
}
I can try to save the element in the global variable but each time when the render is called it initializes a new instance.
Edit:
yes sure. i have this method. I have 2 buttons on screen based on which i render different components. User can made some changes on each component, so i am trying to to use same component so that the changes made in component are persisted. i have tried returning this.accountInfoJSX as well as this.accountInformationMod not its not working. On former it re render the new component and values are lost and on latter it show nothing on screen.
get getCurrentScreen() {
if (this.state.selectedScreen == Screens.accountInformation) {
return this.accountInformationMod;
} else if (this.state.selectedScreen == Screens.myInformation) {
return <MyInformation />;
}
}

Resources