useEffect React hook 使用了怎样的比较过程?
What comparison process does the useEffect React hook use?
让我们从我最喜欢的JavaScript表达开始:
[]==[] // false
现在,让我们谈谈 the React doc 对跳过副作用的看法:
You can tell React to skip applying an effect if certain values haven’t changed between re-renders. To do so, pass an array as an optional second argument to useEffect:
useEffect(() => {/* only runs if 'count' changes */}, [count])
现在让我们考虑以下行为让我摸不着头脑的组件:
const App = () => {
const [fruit, setFruit] = React.useState('');
React.useEffect(() => console.log(`Fruit changed to ${fruit}`), [fruit]);
const [fruits, setFruits] = React.useState([]);
React.useEffect(() => console.log(`Fruits changed to ${fruits}`), [fruits]);
return (<div>
<p>
New fruit:
<input value={fruit} onChange={evt => setFruit(evt.target.value)}/>
<button onClick={() => setFruits([...fruits, fruit])}>Add</button>
</p>
<p>
Fruits list:
</p>
<ul>
{fruits.map(f => (<li key={f}>{f}</li>))}
</ul>
</div>)
}
ReactDOM.render(<App/>, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
添加 'apple' 时,这是控制台中记录的内容:
// on first render
Fruit changed to
Fruits changed to
// after each keystroke of 'apple'
Fruit changed to a
Fruit changed to ap
Fruit changed to app
Fruit changed to appl
Fruit changed to apple
// ater clicking on 'add'
Fruits changed to apple
而且中间部分没看懂。每次击键后,fruits
从 []
变为 []
,如果它们引用不同的对象,这在 JS 中是不相同的。因此,我希望记录一些 Fruits changed to
。所以我的问题是:
React 用来决定是否跳过 effect hook 的具体对象比较过程是什么?
After each keystroke, fruits goes from [] to []
您的印象似乎是 fruits
在每次击键后重新分配给新的 array
,但事实并非如此。
它不是在比较两个新数组,而是在比较同一个标签,该标签在这个特定时间点指向内存中的同一个引用。
鉴于:
var arr = [];
我们可以检查 arr
引用是否随时间发生变化(如果没有发生突变)。
简单示例:
var arr = [];
var arr2 = arr;
console.log('arr === arr ', arr === arr)
console.log('arr === arr2 ', arr === arr2)
arr = [];
console.log('---- After the change ----');
console.log('arr === arr ', arr === arr)
console.log('arr === arr2 ', arr === arr2)
一个用于比较对象的函数实际上是 Object.is
method 的 polyfill。你可以在源代码中看到它:
https://github.com/facebook/react/blob/master/packages/shared/objectIs.js
这是一个在 useEffect
实现中比较 prevDeps
和 nextDeps
的函数:
顺便说一下,在 useState
.
下提到 Object.is
作为比较算法 in the hooks API section of the docs
让我们从我最喜欢的JavaScript表达开始:
[]==[] // false
现在,让我们谈谈 the React doc 对跳过副作用的看法:
You can tell React to skip applying an effect if certain values haven’t changed between re-renders. To do so, pass an array as an optional second argument to useEffect:
useEffect(() => {/* only runs if 'count' changes */}, [count])
现在让我们考虑以下行为让我摸不着头脑的组件:
const App = () => {
const [fruit, setFruit] = React.useState('');
React.useEffect(() => console.log(`Fruit changed to ${fruit}`), [fruit]);
const [fruits, setFruits] = React.useState([]);
React.useEffect(() => console.log(`Fruits changed to ${fruits}`), [fruits]);
return (<div>
<p>
New fruit:
<input value={fruit} onChange={evt => setFruit(evt.target.value)}/>
<button onClick={() => setFruits([...fruits, fruit])}>Add</button>
</p>
<p>
Fruits list:
</p>
<ul>
{fruits.map(f => (<li key={f}>{f}</li>))}
</ul>
</div>)
}
ReactDOM.render(<App/>, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
添加 'apple' 时,这是控制台中记录的内容:
// on first render
Fruit changed to
Fruits changed to
// after each keystroke of 'apple'
Fruit changed to a
Fruit changed to ap
Fruit changed to app
Fruit changed to appl
Fruit changed to apple
// ater clicking on 'add'
Fruits changed to apple
而且中间部分没看懂。每次击键后,fruits
从 []
变为 []
,如果它们引用不同的对象,这在 JS 中是不相同的。因此,我希望记录一些 Fruits changed to
。所以我的问题是:
React 用来决定是否跳过 effect hook 的具体对象比较过程是什么?
After each keystroke, fruits goes from [] to []
您的印象似乎是 fruits
在每次击键后重新分配给新的 array
,但事实并非如此。
它不是在比较两个新数组,而是在比较同一个标签,该标签在这个特定时间点指向内存中的同一个引用。
鉴于:
var arr = [];
我们可以检查 arr
引用是否随时间发生变化(如果没有发生突变)。
简单示例:
var arr = [];
var arr2 = arr;
console.log('arr === arr ', arr === arr)
console.log('arr === arr2 ', arr === arr2)
arr = [];
console.log('---- After the change ----');
console.log('arr === arr ', arr === arr)
console.log('arr === arr2 ', arr === arr2)
一个用于比较对象的函数实际上是 Object.is
method 的 polyfill。你可以在源代码中看到它:
https://github.com/facebook/react/blob/master/packages/shared/objectIs.js
这是一个在 useEffect
实现中比较 prevDeps
和 nextDeps
的函数:
顺便说一下,在 useState
.
Object.is
作为比较算法 in the hooks API section of the docs