Problem Cause and Solution After setState () not re-rendered - React source code analysis

Background problem

Suppose we are developing allows users to fill out a form, such as login page account password form.

return (
	<form>
	  <p>账户:</p>
	  <input type="text" name="firstname"><br>
	  <p>密码</p>
	  <input type="password" name="lastname">
	  <p class="error"> { errorState } </p>
	</form>
);

Which you can see, we have a special area is used to display error messages. errorState we used state (state) is stored in the error message in React . When the user fills out the account password is incorrect, we want to show the user name or password is incorrect information in this area.

We can state our React to store the error message, once the server returns an error message, the error message we deposited into the state array (Array) of them.

Here we use react hook as an example.

// 初始一个空数组,用来储存错误信息
const [errorState, setErrorState] = useState([]);

When we returned from the server receive an error, we want to add the information into an error in our state.

// 变量 newMessage 储存着新返回的错误信息
setErrorState(prevErrorState => {
	const errorMessages = prevErrorState;
	errorMessages.push(newMessage);
	return errorMessages;
});

As can be seen from the above code, we will first remove the existing error information array, as a new element added to the array new error message, then we return the array state.

There was a problem

However, when we tested was found, even though the code runs successfully, React and will not re-render the page, lead to a new error message will not be rendered.

problem analysis

View source code is a good way to learn, which not only allows us to see the root of the problem, can also help us to improve the ability to read the code.

React let's look at the source code, even if we look at why the state is called setting method (setErrorState), React not re-rendering it?

If we call this line setErrorState set breakpoints, and line by line forward, we will see React has the following code:

// _eagerState: 我们传入的新状态,这里是我们传入的错误信息数组
// currentState: 当前状态,也就是还没改变的旧状态
if (is(_eagerState, currentState)) {
  return;
}

From here we can see, React and we will pass the new state, the state is determined by comparing whether to join before re-rendering tasks to the scheduler inside . Here, if the old state and the new state are equal, React direct return, and will not schedule any task of re-rendering.

We look at the details of is () method:

function is(x, y) {
  return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y;
}

Although this code looks very confusing, but do not stress. We only need to look at the first part of the code:

return x === y

We can know what the core idea of this code is, without having to tangle in the latter part of the details , because they are essentially nothing to do with the problems we are currently experiencing. This is also a technique to read the code .

From this you can see why React will not re-render us the error message. Although we have a new error message as a new element is inserted into the old array, but in this code, React and does not check whether the array element is changed, it will only check the references of the array itself if there is a change.

Therefore, from the eyes React point of view, is still the same array of references (references which represents the memory location), it means the state is not updated, it will not re-render our error messages.

Solve the problem

To solve this problem, we can clone a new array, and then we insert new elements into it, and then use the new clone array to set our error state.

The new clone is a new array array occupies its own place in memory, and therefore has a reference to their own, so in the eyes React view, the array before the array is completely different, so we'll re-rendering task.

// [...errorState] 为 JavaScript 里的语法糖,会克隆并返回一个装有相同元素的新数组
setErrorState(prevErrorState => {
	const errorMessages = [...prevErrorState];
	errorMessages.push(newMessage);
	return errorMessages;
});

The code is changed as described above, React we will re-render the error message states it!

Author still learning, if there is something wrong, please point out and contain, thank you!

Author: David Chou (Vancouver SFU computer student)

Published 14 original articles · won praise 8 · views 2210

Guess you like

Origin blog.csdn.net/vandavidchou/article/details/102618866