Nested State for Large Forms React - reactjs

When dealing with large form data, with regards to performance should that state be nested, or should you not nest state? For instance consider if you had a form with 100 or more fields:
Option 1
state = {
formData: {
formItem1: value,
formItem2: value
}
}
Option 2
state = {
formItem1: value,
formItem2: value,
formItem3: value
}
The second option above (not nesting) - would seem to pollute the state with a lot of fields. The first option above (nesting) - I am not sure if this would cause performance issues on large forms when you update state. For instance, to update state for option 1 above:
this.setState({
formData: {
...this.state.formData,
formItem1: newValue
}
});
Because this is technically creating a new object for formData - would ALL form fields go through the re-render process since each one's state has been updated - and thus cause performance issues for huge forms?

you can directly modify nested state but you can do it as so you can use nested state as well and use your 1st option -
let temp = this.state.formData;
temp.formItem1 = newValue;
this.setState({formData:temp});
this will work

Thanks to react official docs :
setState() will always lead to a re-render unless shouldComponentUpdate() returns false. If mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
I would recommend to store only those formItems in your state which are dependable to re-render the component. You can store all other formItems in variables and add them in your component state if necessary. This whole purpose is to avoid unnecessary re-renders.
Sometimes the changed state is relevant for the rendering, but not under all circumstances. For example when some data is only conditionally visible.

Related

Why do we use spread operator or object.assign

Why do we use/is advided to use immutable approach in changing the state
for example, why do people create a copy of a state before changing
For example
this state = {
a: 'apple'
b:'ball'
}
and then to change state
const copyState = {...this.state}
copyState.b = bunny
this.setState({...copyState})
like, why not just
this.setState({b:bunny})
Because in React working with the state is completely functional process. Meaning the state is immutable. And if you would write this.setState({b: 'bunny'}) and print out this.state it would only print out b: bunny and not a: 'apple' as well.
Also your example can be simplified. Instead of assigning a copyState variable to an object, you could write the following:
this.setState({
...this.state,
b: 'bunny',
})
TLDR;
You cannot add values to the state, it is readonly. You need to reassign the state.
Imagine you have a form for editing a user. It’s common to create a single change handler to handle changes to all form fields. It may look something like this:
updateState(event) {
const {name, value} = event.target;
let user = this.state.user; // this is a reference, not a copy...
user[name] = value; // so this mutates state ?
return this.setState({user});
}
The concern is on line 4. Line 4 actually mutates state because the user variable is a reference to state. React state should be treated as immutable.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
Why?
setState batches work behind the scenes. This means a manual state mutation may be overridden when setState is processed.
If you declare a shouldComponentUpdate method, you can’t use a === equality check inside because the object reference will not change. So the approach above has a potential performance impact as well.
Bottom line: The example above often works okay, but to avoid edge cases, treat state as immutable.
Source: Handling State in React: Four Immutable Approaches to Consider
Short answer is to avoid odd bugs and this leads to components that are hard to optimize.
React components refresh or rerender views based on updates to props and state. setState ensures that components are re-rendered based on changes to state. If we start mutating state directly and then calling setState we might end up missing Component refreshes.
For a detailed understanding you can check out -
https://daveceddia.com/why-not-modify-react-state-directly/

Haze about 'setState' in React official doc

I am reading react.js official docs.
Here is one of them.
I am confused about this paragraph:
setState() will always lead to a re-render unless
shouldComponentUpdate() returns false. If mutable objects are being
used and conditional rendering logic cannot be implemented in
shouldComponentUpdate(), calling setState() only when the new state
differs from the previous state will avoid unnecessary re-renders.
Question: Why calling setState() will avoid unnecessary re-renders if mutable objects are being used and conditional rendering logic cannot be implemented in shouldComponentUpdate()?
shouldComponentUpdate deep-dive might help you
Calling setState() will always trigger a re-render of the component(unless you have defined shouldComponentUpdate()). But keeping performance and efficiency in mind, we want the component to re-render only if the state value has actually changed.
This is where shouldComponentUpdate() lifecycle method comes into play.
In this method, a check can be done to determine whether the state value has changed. If state has changed, returns true and the component re-renders.
Mutable objects refer to Arrays, objects etc in javascript. Numbers and Strings are immutable.
Mutable object example:
const a = [1,2]; // memory address of a is 0xff456e
a.push(3); // memory address of a is 0xff456e(same)
Immutable object example:
let b = 'Hello'; // memory address of b is 0xee789e
b = 'World'; // memory address of b is 0xee789f(different because its a new object created with value 'World')
If your component is a PureComponent, then react by default will define the shouldComponentUpdate() to reduce unnecessary re-renders. But you need to use immutable objects for that to work correctly(i.e create a new array or object manually and assign to your state, else your component won't re-render correctly).
So, the point they are making is this : Don't call setState() unless the state value has actually changed if your using a normal react component without a shouldComponentUpdate() check to avoid situations like this:
this.setState({ items: [1, 2, 3] }); // re-render once
// lot of code goes here
this.setState({ items: [1, 2, 3] }); // re-render twice
Note: Although the value of items is unchanged, there is a wasteful re-render of the component caused as shown above. So, avoid setting state if there is no change of value.
I think you read that wrong.
It's a two term conditional:
IF
mutable objects are being used
AND
conditional rendering logic cannot be implemented in shouldComponentUpdate()
THEN
[you should call] setState() only when the new state differs from the previous state [so it] will avoid unnecessary re-renders.
(Alteration by me are in brackets.)
Basically, it means that it's up to you to test if you should call setState if you can't rely on React's internal tests due to technical limitations on your side.
The doc wanted to say that in the following conditions, the re-render will not happen:
If shouldComponentUpdate hook returns false.
If mutable objects are being used.
If some conditional logic is not used for re-render like force update inside shouldComponentUpdate hook.
If the effect of calling setState method only change the previous state value.
BTW, I'm still not satisfied that I couldn't make clear enough. :(:

React: What is the performance penalty of calling setState after mutating the state directly in the component?

Since the component's render method is called with each setState*, I was wondering about the performance penalty if I directly modify the state properties, call setState({}) with an empty object, and let the component fully render itself. This has an interesting side effect in the state management: The state in this case used as a mutable object rather than immutable one. Since the component will re-render with the new state values after the setState call, it will reflect the new values in the view. Of course, mutating the state is not recommended by the React team as they suggest the state should be treated as a readonly object, but nevertheless dealing with a mutable object becomes easier to do state management in some cases.
I know this is not the best practice and probably will raise some eyebrows immediately, but I cannot stop and ask for the performance impact or any other potential problems it may cause in a typical application.
Take a look at the following example for a simple demonstration: https://codesandbox.io/s/k5zy9zw8kv
So, please let me know what you think.
Thanks.
* Unless shouldComponentUpdate has been implemented within the component and returning false based on the current state and the nextState value.
PS: My personal opinion, for state management, it is better to use MobX for mid-sized to large scale applications. My question is mostly for relatively small applications. I think both react and redux are making state management unnecessarily complex than it should be. As a developer with OO background I would like to see simpler and more elegant solutions.
This is a terrible idea.
1. Officially unsupported
Direct state mutation is undocumented, unsupported and untested, so the React team can change the behaviour across versions (without testing/documenting it).
2. Breaks lifecycle methods
You break several lifecycle methods such as componentDidUpdate as prevState will not be the state before the mutation, so you give up your option of using these methods should you need them in the future.
3. Keep state shallow instead
dealing with a mutable object becomes easier to do state management
You probably get this feeling when you have deeply nested states, so modifying a nested property (eg. product.quality) requires cloning the whole object (eg. products) first.
It's recommended to keep your states as shallow as possible, both for state change simplicity and easier performance optimisation. Eg. if you state is shallow, declaring it as PureComponent will avoid it calling render when parent component re-renders with no changes to the child component.
In your example, you can move the state to Product instead:
class Product {
state = { quantity: 0 };
...
this.setState(prevState => ({ quantity: prevState.quantity + 1 }));
}

How to have different react components share and acknowledge each other's states?

I've frequently encountering dynamic components not being able to update each other directly. Multiple models that update each other's attributes but not their views.
model2View.onClick=() {
model1.change;
model1View.forceUpdate();
}
i've often resorted to throwing in callback functions into the mix which is just a wrapper that updates the model and forceupdate the overhead view after change.
it gets worse when the model update is a modelside function that updates more than one model, in which case I've been using the nearest ancester view to perform the forceupdate.
model2View.onClick=() {
the following 3 could be wrapped in one method on model1
model1.change;
model2.change;
model3.change;
modelsWrapperView.forceUpdate();
}
After many force updates, I am just wondering if that's the way react was meant to be used or I'm missing something.
Here's an oversimplified example of the problem i'm trying to solve:
https://jsfiddle.net/x3azn/ann6qb30/1/
You are attempting to mutate an object that is part of your state and React won't re-render because it doesn't know that something has changed. That's why you're having to call forceUpdate.
You should treat state as immutable and use setState to update it (updated demo):
class TransformersApp extends React.Component {
toggleDeception() {
// Create a new object rather than mutating the existing one.
var newTransformer = Object.assign({}, this.state.transformer, {
isDecepticon: !this.state.transformer.isDecepticon
});
// Update the state.
this.setState({
transformer: newTransformer
});
}
}
This is made clear by the docs for setState:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
You may find it helpful to use something like Immutable.Map as your state object as that will prevent you from mutating the state at all.

What is the correct way of setting state variables in Reactjs and what is the difference between these approaches?

I was working with React JS and I was wondering the difference between calling setState() twice to set two different state variables like this:
this.setState({fruit1: “apple”});
this.setState({fruit2: “mango”});
AND
calling setState() once and passing both state variables as JSON like this:
this.setState({fruit1: “apple”, fruit2: “mango”});
Also what is the better practice: putting state variable names in double quotes like this: this.setState({"fruit1": “apple”}) or simply ignoring the quotes?
From React documentation:
NEVER mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.
setState() will always trigger a re-render unless conditional rendering logic is implemented in shouldComponentUpdate(). If mutable objects are being used and the logic cannot be implemented in shouldComponentUpdate(), calling setState() only when the new state differs from the previous state will avoid unnecessary re-renders.
So, use this.setState({fruit1: “apple”, fruit2: “mango”});
For the second question you can look here and here
Inside a React event handler (that is, a function called from a React-based onChange={...} property and the like), multiple calls to setState are batched and the component is only re-rendered a single time. So, there's no difference between
handleClick: function() {
this.setState({fruit1: "apple"});
this.setState({fruit2: "mango"});
}
and
handleClick: function() {
this.setState({fruit1: "apple", fruit2: "mango"});
}
However, outside of the React event system, the two calls to setState will not be merged unless you wrap them in a function passed to React.addons.batchedUpdates. This is normally not something you have to worry about, but may become an issue if you start setting state in response to asynchronous events (e.g. timers, promises, callbacks, etc). For that reason, I would generally recommend the second form (with the two objects merged into one) over the first.
Here is a detailed explanation of React States and setState() method.
States (and props) are only two reasons why React re-renders/recalculate the DOM. It means if we change State, we are telling react to change the related behaviour of our app.
State is a Java-Script object with key:value pair. Now we may have many States (many key:value pairs) and let's say at certain point only one state is changing. in that case we may use this.setState() method to change only that specific state.
state = { fruit1: 'mango', fruit2: 'apple' }
let's say we want to update fruit1: 'watermelon'.
Here we can say:
this.setState( {fruit1: 'watermelon'} );
Here, we did not say anything about second state (fruit2), so react will merge changed state (fruit1) with old state (fruit2).
While, we can also say:
this.setState( {fruit1: 'watermelon' ,fruit2:'apple'} );
But it is not necessary.
Correct and Re-commanded way of setting/changing State:
From React Official docs:
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
So here is a better way to do it:
If we are updating the counter or calculating something:
this.setState((prevState,props) => {
return {
{ counter: prevState.counter+1; }
}

Resources