useEffect React钩子使用什么比较过程?

问题描述 投票:3回答:2

让我们从我最喜欢的JavaScript表达式开始:

[]==[] // false

现在,让我们说一下the React doc关于跳过副作用的说法:

如果重新渲染之间某些值没有改变,您可以告诉React跳过应用效果。为此,将数组作为可选的第二个参数传递给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使用什么确切的对象比较过程来决定是否跳过效果钩子?

javascript reactjs react-hooks
2个回答
1
投票

用于比较对象的函数实际上是Object.is method的polyfill。你可以在源代码中看到它:

https://github.com/facebook/react/blob/master/packages/shared/objectIs.js

这是一个在prevDeps实现中比较nextDepsuseEffect的函数:

https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.js#L286


顺便说一句,在Object.is下,in the hooks API section of the docs被提及作为比较algorhitm useState


1
投票

每次击键后,水果从[]变为[]

看起来你的印象是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)
© www.soinside.com 2019 - 2024. All rights reserved.