React state validation - reactjs

I would like to perform state validation on react component on every setState call and if new state is invalid, use another - valid state.
For example, if I have slider, with 4 pages and I want to do
this.setState({
page: 5
});
In my validation function I'd check whether new state's value is greater than pages count and if so, I'd set 4 (total pages) instead of provided 5.
Is this possible?
Thanks

There doesn't seem to be a great answer for this, after trying many things.
If there is an answer to the question it might be that there's no good way to do it. I think it doesn't hurt to look at potential solutions though and the drawbacks of each one.
Solution 1
Use componentWillUpdate. This is deprecated.
Solution 2
Validate state on render - but in your case and in most others, validation may lead to setState, which react tells you never to do in render(), but doesn't go into any detail about what will actually happen. Of course, you would have to be careful to prevent infinite loops, but if you call setState in render() upon some condition which cannot logically result in an infinite loop, then what unintended side effects could occur?
Solution 3
As above, make a wrapper function to both validate and set state. But this is no good in my opinion because any state changes done with set state directly cannot be validated. Not only does setState directly not call your validation, but your validation also does not run on the items in the initial state. You might say, why would you give your component an initial state that's invalid, but I don't care, if I want to validate state I want it to validate 50000% of the time and no less.
In a complex form example, there are other issues with this. What if the validity of one field depends on the state of another field? Surely then, a function to re-validate a field when it changes is not enough. Some people will say to test the field being passed in and dispatch multiple events for re-validation, but again, this just isn't acceptable to me. Its not fullproof, it can lead to bugs, and make things hard to test.
Solution 4
Use componentWillReceiveProps. Not only is this deprecated, but its also static, meaning that you don't have access to the component instance. For some components this is fine because you can still modify the state that is returned, but if your component has data outside of state and props then you cannot access it, in addition to not being able to use non-static methods, which in my opinion makes this method pretty useless in many situations.
Solution 5
Haven't tested this one (bear with me, its fairly nuts), but you can override setState function in your component. Insert a callback into every setState instance. Track how many times setState is called and how many times the setState callback is called. Inside the callback, you can check the two counters stored in the object to see if the last callback is currently running, then, if it is, run one function which validates all state. On render, set both of the counters back down to zero. I don't recommend this by any means. It may work but its a pretty major hack.
Solution 6
You can use componentDidUpdate, but this is inefficient. You will be blindly setting state with a value that was not validated then letting your component render only to validate it after and possibly call render again. Once again you have to be careful to avoid infinite loop while calling setState in componentDidUpdate. I read elsewhere that at least if you set the state here, the DOM will only re-draw once. In other words, it doesn't draw immediately after render() but waits until componentDidUpdate is triggered and re-calls render if state changes in there. This seems like maybe its the only solution I know about that react only warns about without telling you explicitely not to do this. In your case, the efficiency does not matter, but what if the state you were trying to validate was a 100 field form with a very expensive render method. Now, on every key down you've essentially doubled the amount of work that react has to do to render your components, causing them to first render without being validated, and then filtering and/or validating them for a very likely second render.
Additional Issues
In my case, i'm working on a form and not a simple component like you described above. I may go with a mix of solution 3 and 5. Its more complicated then I want though. It involves using one function to filter, generate errors, and set the state for each field (ie. solution 3). And then on componenetDidUpdate I may look for state keys whose values are different from the last value that the field was validated with. The second step here has many ways of doing so, all of which are messy and inefficient. To make it worse, they practically never run under normal circumstances because I always use the first function to update and validate their state, so this makes testing it harder. It's like leaving some fallback in my app that seems to work but during the entire development process it never triggers except for like the one time that I decided to test it. Seems like a bad idea to me.
There are additional efficiency concerns I also won't get into which relates to trying not to re-validate a field if it has the same value it was validated with last time. This is a whole other can of worms, but basically what it boils down to is that you should be able to not only validate a state before render, but you should have access to the previous state as well, so you can save some cpu time and only validate the fields that changed. For example, if you have a very long textarea with some complex regex, it would be nice to not validate that on every component render even if its a separate field that is changing.
Afterthoughts
I'm very thoroughly disappointed that react seems to provide no legitimate option for this. Seeing as you can call setState many times in one operation, and each one will be queued, how is it that they don't provide us with one callback after all state changes are resolved and we're about to render? Well if you think about it, the render function itself is this callback, because I think its only ever called after setStates are resolved, but again, its evil to call setState on render, and it would be a million times cleaner to have render() simply receive the correct state, so I don't see how this is very useful.
Does anyone know why they decided to get rid of componentWillUpdate?

Yes it is certainly possible. Simply wrap setState so that you can do your validation prior to the actuall call. Something like:
function checkThenSet(newState){
// do validation here
if (validation) {
this.setState(newState);
} else {
// validation failed
this.setState(otherState);
}
}
And if your updating your state by way of user interaction, then your render function would look like this
var MyComponent = React.createClass({
checkThenSet: function(newState) {/* Same as above */},
render: function() {
return (<input
type="text"
value={this.state}
onChange={this.checkThenSet}
/>);
}
});

I'm not sure, but shouldComponentUpdate method might help you.
class Example extends React.Component {
constructor(){
super();
this.state={
count: 0
}
this.handleClick = this.handleClick.bind(this);
this.reset = this.reset.bind(this);
}
shouldComponentUpdate(nextProps,nextState){
return nextState.count <= 4
}
handleClick(){
const newState = this.state.count + 1;
this.setState({count: newState})
}
reset(){
this.setState({count: 0});
}
render(){
return <div>
<p>State: {this.state.count}</p>
<button onClick={this.handleClick}>Click Me</button>
<button onClick={this.reset}>Reset</button>
</div>
}
}
React.render(<Example />, document.getElementById('container'));
But it also depends on your logic whether component should be updated. fiddle example
I hope it will help you.

Related

What's the idea behind useState functionality in ReactJS?

I am learning ReactJS and I understand the benefits of functional programming. However, I am a little concerned about the actual useState approach. If we assume a variable to be changed, then why declaring it const in the first place?
I see that I can simply use let number = 4; and then render it like this <p>{number}</p>. What I cannot do however is to re-render it automatically just by changing it, for example using onClick event like this <p onClick={() => ++number }></p>. Why is it that so? Is there a specific reason I am missing why it was implemented the way it is? I mean why the developers have decided that if the value needs to be re-rendered upon change, then it must be a const value declared with the help of useState functionality?
I am asking this because I am suspecting I am missing some good points behind this and I would like to understand them.
The variable is declared as a const because you are not allowed to set it directly. In React the state itself is immutable. You are just allowed to change it over setState (or setNumber in your case) or with actions if you use redux.
But why is that? It may seem unnecessary cumbersome in the beginning
First of all, if your variable number changes, react has to trigger a rerender.
If the state is mutable, it requires data-binding because if the number is set, it has to update the view.
In javascript, data-binding works for simple objects, but not well for arrays. Vue.js for example, as an alternative that uses two-way data binding, had a lot of trouble in its early versions when dealing with arrays. That's why there are now only seven predefined methods to interact with arrays (which they added later to solve that problem). Vue Js Array Methods
So a simple reason to declare the state as const is that it works better with arrays. And if you watch the example you gave, setNumber(number + 1) is not that much more to write than number++. But setState(newArray) works, and newArray[i] = newElement would not work, because due to javascript limitations this cannot trigger a rerender.
Secondly, it is a nicer design concept. Think of your component as a function, that returns a view to a state. And if the state changes, you get a new view. It simplifies relationships between properties in your component. If you were allowed to change your state while rendering your component, it would create a mess.
The problem is that you're thinking of a functional component as if it was stateful. But it isn't. It's a function and once you run it, that's it.
Take this example:
function useState() {
let value = 1
function setValue(v) {
value = v
}
return [value, setValue]
}
function myFunction () {
const [value, setValue] = useState(); // <----- we use const here
return null
}
Even though we're using const, the value variable only exists within the function, once the function returns that's it. It's the same for components.
The actual value of value is stored in a whole different scope, where useEffect has access to.
Here's a deep dive on how react works internally if you're interested
React works in render cycles, i.e. some state is declared, the DOM (UI) is computed during the "render phase", and then flushed to the actual DOM during the "commit phase".
Within each cycle state is considered constant (const in JS simply means a variable can't be assigned a new value, you could just as easily declare it with let or var instead and react would work the same) but for react's purpose, state is constant during a render cycle. When it is updated via one of the state update methods, react then kicks off another render cycle (update state, compute diff, commit to DOM) and re-renders when necessary.
This process is important and the reason why external state mutations are considered anti-pattern, it goes against the react workflow and leads to buggy code or worse, UI that doesn't update as expected.
React component lifecycle
I cannot do however is to re-render it automatically just by changing
it, for example using onClick event like this <p onClick={() => ++number }></p>. Why is it that so?
React state updates use a process called reconciliation to figure out what changed and what to re-render. In really simplistic terms, when react state is updated it is updated with a new object reference so a shallow object comparison can more quickly detect that the component state updated.
Declaring state and doing ++number simply changes the value but not the reference, and would be considered a state mutation, an anti-pattern in react.

How to intercept setState function to capture individual state changes?

I am implementing activity logging in a React application to track users activity and a practical way would be to simply log each change to the component state. The state object is large in my scenario, so I would like to capture only the changed elements, which would also be easier to read in the log. To do so it would be ideal to intercept every setState call so that I can get the specific pieces that changed in the state. I have most of all the state in a higher level component so I would have to do this only in one component basically.
I don't want to do this in every call to setState across all my component's code. I want to be able intercept it for once an for all at a component level.
Is there an elegant way of intercepting setState that does not involve creating an alternate setState function stub?
Any tips greatly appreciated. Thanks.
The following lifecycle methods will be showing the changes when state/props changes in a component. You can use the state object to determine the activity logging.
// Happens before the component update
componentWillUpdate(object nextProps, object nextState)
// Happens after the component update
componentDidUpdate(object prevProps, object prevState)
For example,
componentDidUpdate(prevProps, prevState) {
if(prevState.isLoadingData !== this.state.isLoadingData) {
writeToActivityLog('user-requested-new-data');
}
}
The state object is large in my scenario, so I would like to capture
only the changed elements, which would also be easier to read in the
log.
For this scenario, you can make use of utility library like lodash to get all the changed properties or do a deep equal between this.state and prev/nextState. Even then you may require conditions to log different events.

increase react application performance

I am currently developing a react redux based web application which displays large amount of data on the UI. When the data size increases, the frame per second decreases. Also, certain forms displaying components take longer and appear to be sluggish.
If someone could guide me on correct rendering method or some coding standards needed to be followed for such applications, it will be a great help.
-Thanks
I am currently checking whether my application uses react lifecycle components (explicitly by any other developer). I am also suspecting the way in which components are rendered.
Hello and welcome to StackOverflow!
Your question is very generic, so it's hard to pinpoint exactly how to resolve it.
I guess the first thing I'd do is take a look in chrome's performance tab in the developers tools. You can use it to profile you application and see what functions take the longest.
You can find helpful information here and here.
This will give you a good starting point.
As far as profiling a React application, you can take a look at React's Dev Tool profiler, more info can be found here.
You might also want to make sure to avoid the deprecated lifecycle functions, as they are known to cause performance issues. Those are:
componentWillMount
componentWillRecieveProps
componentWillUpdate
And make sure you perform all HTTP requests after components mount.
If everything fails, you should look into memoization techniques. Memoizing is basically saving the result of a function call in memory, so the next time your function is called with the same arguments, you don't recalculate the output. For that you can use React's builtin memo feature to memoize complete components, and a selector (like reselect) to memoize redux computations.
Please Check Prevent Unnecessary Rendering
All children in component re-renders when its props or state gets updated. This is the default behavior, and, since React updates only the relevant DOM nodes, this process is usually fast. However, there are certain cases where the component’s output stays the same regardless of whether the props have changed.
To alter the default implementation, you can use a lifecycle hook called shouldComponentUpdate(). This lifecycle hook doesn’t get invoked during the initial render, but only on subsequent re-renders. shouldComponentUpdate() is triggered when the props have changed and it returns true by default.
shouldComponentUpdate(nextProps, nextState) {
return true;
}
If you’re sure that your component doesn’t need to re-render regardless of whether the props have updated or not, you can return false to skip the rendering process.
class ListItem extends Component {
shouldComponentUpdate(nextProps, nextState) {
return false
}
render() {
// Let the new props flow, I am not rendering again.
}
}
Alternatively, if you need to update only when certain props are updated, you can do something like this:
class ListItem extends Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.isFavourite != this.props.isFavourite;
}
...
}
For example here, we’re checking whether the current value of isFavourite has changed before each render (nextProps holds the new value of the prop) and if yes, the expression returns true. The component gets re-rendered. The changes in any other props won’t trigger a render() since we’re not comparing them in shouldComponentUpdate().
Attention Replacing ‘componentWillReceiveProps’ with ‘getDerivedStateFromProps’
With the release of React 16.3, some new lifecycle methods have been
introduced, and release of React 17 will deprecate some lifecycle
method.
You can find helpful information here

React - how to use the lifecycle methods

I keep encountering the same problem with React. I feel I should be using the lifecycle methods. (Other than just componentWillMount and componentWillReceiveProps). But they never seem to meet my purpose. Here are 2 examples:
Asynchronous loading
My parent component loads some data with AJAX. A grandchild component needs this data - which is passed down via props. Because of the timing the data may be available when the child component is mounted or not. I don't know whether to put the code in my grandchild component which depends on these props in componentWillMount() or in componentWillReceiveProps(). I end up having to put it in both. (Or in a method they both call).
Lifecycle methods are either called on the initial render or not. I want them to be called on both.
My component gets some data. (Using getStateFromFlux - a mixin provided by Fluxxor). This occurs several times during the cycle of loading the data with various flags set onto the retrieved data object: unloaded, loading and loaded let's say. This change of state causes a re-render.
I only want to render and show the data if there is something to show. So - my render method has the first line:
if data.loadState != 'loaded'
return '<span />'
Ok. Well. I thought - there must be a lifecycle method to fix this. So I've done this:
shouldComponentUpdate: function (nextProps, nextState) {
if nextState.loadState == 'loaded'
return true
else
return false //stops the render. Good.
}
At last I thought - I have used a lifecycle method.
But, alas, while this does stop the render being called in some cases - when there is no data - I still can't remove the hacky looking line about
if data.loadState != 'loaded'
return '<span />'
This is because shouldComponentUpdate is not called for the initial render. When this component first renders there is no data. loadState is 'unloaded'. The render method is still called. And I still need to avoid displaying the UI (with empty data fields).
In general terms - the lifecyle methods are either called only on the initial render or only on subsequent renders. For most of my uses cases this is singularly unhelpful. I want a method which is agnostic to whether it is the first render or a subsequent one.
What am I missing about React? (The only thing I can think of is is that it is designed to be used with an initial render server-side when you can be sure of your data - then once in the browser the lifecycle methods are about detecting changes).
Thanks
Don't know about loading but with unloading I would suggest;
if (this.props.data.loadstate == 'unloaded') return null;
Have that as the first line of the render. As you noted shouldComponentUpdate only applies to updates.
You're right that you should be using the lifecycle methods, they're awesome and let you hook into your components in a much more in depth way. But I don't think this is the case for your current situation
You could just conditionally render the grandchild only when the data is loaded by the parent and passed to the child. Then you'd only need the check in the child. It would look something like this:
// Child render method that has been passed data loaded by the parent
render: function() {
var grandChild = null;
if (this.props.data) {
grandchild = <GrandChild data={this.props.data} />
}
return (
<div>
{grandchild}
</div>
)
}
In this case, you only pass a data prop to the child component once the data has loaded. Thus, you're guaranteed that when the grandchild component does render, it will have the data that it needs. Although I'm not sure why you are so averse to displaying empty data fields, this should solve the problem.
You're correct, there is no React lifecycle method that fires regardless of whether it's the initial render or not. That being said, if you have to do both, you can always a combination of componentDidMount and either componentDidUpdate or componentWillReceiveProps. I'm not 100% sure why they did this, but a couple reasons that come to mind:
Ensures that React will not need to re-render a component before the initial render (ie. changing state in componentWillReceiveProps, triggering an update before the initial render). I'm not too familiar with the code-base, but I can easily see that causing problems.
Performance boost for the initial render to let your content load faster while the virtual DOM is initialized
I hope this helps solve your problem and sheds some light on the lifecycle methods!

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