我是新来的,与React Hooks功能组件相关,我有一些问题需要解释,谢谢:
:我如何在重新渲染之前对某些状态进行深入比较?我看到了反应。Memo只有第二个论点仅用于修改道具的比较,但是国家呢?当前,它使用对象。I进行比较,我想修改此功能。
usememo的Usecallback的原则是什么?我已经调查了React源代码,但仍然不知道该如何执行此操作。有人给我一个简单的例子来说明如何知道如何缓存每个渲染的值?
Q1:在重新渲染之前,我如何对某些状态进行深入比较?
在下面的摘要中,我向您展示了对状态进行深入比较的一种方法。
Q2:Usecallback,UseMeMo?
的原理是什么 useMemo
旨在在您有一些昂贵的计算情况下要记住结果的情况。因此,昂贵的计算仅对inputs
的每个唯一组合进行一次。
useCallback
旨在避免重新创建不需要重新创建的内部功能。除非依赖项数组中列出的某些变量更改。通常用作性能优化。
根据React文档:
usecallback
将回调传递给优化的儿童组件时,这很有用,这些组件依靠参考均等性来防止不必要的渲染(例如,shordcomponentupdate(。
注意:
状态更改是为了引起重新渲染。为什么要在重新渲染之前对其进行深入比较?如果更改,React必须重新渲染。这就是它的工作方式。
如果您想改变某些东西而不引起重新渲染,请查看useRef
钩子。这正是它的作用。ref
对象在每个渲染中保持不变(仅当组件被卸载然后重新安装时更改(。
https://reactjs.org/docs/hooks-reference.html#useref
useref
USEREF返回一个可突出的Ref对象,其.Crurnent属性被初始化为传递的参数(初始值(。返回的对象将持续到组件的整个生命周期。
(...(
但是,useref((对不比ref属性更有用。对于,请保持任何可变值的方便,类似于您在类中使用实例字段的方式。
代码
比较Newstate和Laststate
function App() {
const [myState, setMyState] = React.useState('Initial state...');
const lastState_Ref = React.useRef(null);
const stateChanged_Ref = React.useRef(null);
if (lastState_Ref.current !== null) {
lastState_Ref.current === myState ? // YOU CAN PERFORM A DEEP COMPARISON IN HERE
stateChanged_Ref.current = false
: stateChanged_Ref.current = true;
}
lastState_Ref.current = myState;
function handleClick() {
setMyState('New state...');
}
return(
<React.Fragment>
<div>myState: {myState}</div>
<div>New state is different from last render: {JSON.stringify(stateChanged_Ref.current)}</div>
<button onClick={handleClick}>Click</button>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
更新:
从您的评论中,您对props
的能力是使用React.memo
。它将对您的道具进行比较。请参阅下面的摘要。您会看到常规Child
每次都会重新渲染,如果阵列propA
保持不变,则包裹在React.memo
中的ChildMemo
不会重新渲染。
react.memo
react.memo是一个高阶组件。它类似于react.purecomponent,但对于功能组件而不是类。
如果您的功能组件在相同的道具下呈现相同的结果,则可以将其包装在呼叫中。这意味着React会跳过渲染组件,并重复使用最后一个渲染的结果。
默认情况下,它将仅比较道具对象中的复杂对象。如果要控制比较,也可以提供自定义比较功能作为第二个参数。
这是对这种情况的React Docs建议:
https://reactjs.org/docs/hooks-faq.html#how-do-i-i-implement-shouldcomponentupdate
function App() {
console.log('Rendering App...');
const [myState,setMyState] = React.useState([1,2,3]);
const [myBoolean,setMyBoolean] = React.useState(false);
return(
<React.Fragment>
<button onClick={()=>setMyBoolean((prevState) => !prevState)}>Force Update</button>
<Child
propA={myState}
/>
<ChildMemo
propA={myState}
/>
</React.Fragment>
);
}
function Child() {
console.log('Rendering Child...');
return(
<div>I am Child</div>
);
}
const ChildMemo = React.memo(() => {
console.log('Rendering ChildMemo...');
return(
<div>I am ChildMemo</div>
);
});
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
关于状态,我认为您不应该尝试实现这一目标。如果国家发生变化,它应该重新渲染。实际上,如果状态引用(对象或数组(保持不变,则不会重新渲染。因此,如果您不更改state
参考(例如从刮擦相同的数组或对象重新创建(,则您已经将该行为从开箱即用。您可以在下面的摘要上看到:
function App() {
console.log('Rendering App..');
const [myArrayState,setMyArrayState] = React.useState([1,2,3]);
function forceUpdate() {
setMyArrayState((prevState) => {
console.log('I am trying to set the exact same state array');
return prevState; // Returning the exact same array
});
}
return(
<React.Fragment>
<div>My state is: {JSON.stringify(myArrayState)}</div>
<button onClick={forceUpdate}>Reset State(see that I wont re-render)</button>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
添加到 cbdev420 说的是,这是一个备忘单的链接,该链接可以很好地解释如何使用大多数钩子,如果它可以帮助您https://reeact-hooks-cheatsheet.surge.sh/