javascript - usePreviousDistinct 有 useEffect 和没有 useEffect 之间的区别
问题描述
我需要一个钩子来获取特定状态的先前不同值。它看起来像这样,它似乎工作:
function usePreviousDistinct(state) {
const prevRef = useRef();
useEffect(() => {
prevRef.current = state;
}, [state]);
return prevRef.current;
}
我还看到react-use 包usePreviousDistinct
中有一个钩子,但方法与我的不同。
import { useRef } from 'react';
import { useFirstMountState } from './useFirstMountState';
export type Predicate<T> = (prev: T | undefined, next: T) => boolean;
const strictEquals = <T>(prev: T | undefined, next: T) => prev === next;
export default function usePreviousDistinct<T>(value: T, compare: Predicate<T> = strictEquals): T | undefined {
const prevRef = useRef<T>();
const curRef = useRef<T>(value);
const isFirstMount = useFirstMountState();
if (!isFirstMount && !compare(curRef.current, value)) {
prevRef.current = curRef.current;
curRef.current = value;
}
return prevRef.current;
}
我想知道我是否没有理解某些东西或遗漏了什么。我的版本也正确吗?
在我的测试中我找不到区别: https ://codesandbox.io/s/distracted-mayer-zpym8?file=/src/App.js
解决方案
useEffect()
与useRef()
(您的版本)一起不显示最新值。useRef()
withoutuseEffect()
为您提供正确的值,因为它同步运行,但没有异步带来的优势。useEffect()
withuseState()
为您提供正确的值,但可能会触发不必要的渲染(可能会增加不必要的开销)。
您的版本看起来像预期的那样工作,因为显示的旧值是您希望看到的新值。但实际的新值并不是你想要的。
例子:
import React, { useState, useEffect, useRef } from 'react';
export const MyComponent = function(props){
const [state, setState ] = useState(0);
return <React.Fragment>
state: { state },<br />
with useEffect: { usePreviousDistinctUE( state ) },<br />
w/o useEffect: { usePreviousDistinctR( state ) },<br />
<button onClick={ function(){
setState( state + 1 );
} }>
increment
</button>
</React.Fragment>;
};
const usePreviousDistinctUE = function( value ){
const prevRef = useRef();
useEffect(() => {
prevRef.current = value;
console.log('with useEffect, prev:', prevRef.current, ', current:', value);
}, [value]);
return prevRef.current;
};
const usePreviousDistinctR = function( value ){
const prevRef = useRef();
const curRef = useRef( value );
if( curRef.current !== value ){
prevRef.current = curRef.current;
curRef.current = value;
}
console.log('w/o useEffect, prev:', prevRef.current, ', current:', curRef.current);
return prevRef.current;
};
页面上显示的值是相同的,但在控制台中它们是不同的。这意味着useEffect()
版本中的值已更改,只是尚未显示在页面上。
如果您只是添加另一个钩子来更新任何不相关的内容(保持其他所有内容不变),那么页面(可能*)会神奇地再次显示更新的值,因为页面被重新渲染并显示先前已经更改的值。现在你眼中的值是错误的,但它没有改变,只显示:
// ...
with useEffect: { usePreviousDistinctUE( state ) },<br />
w/o useEffect: { usePreviousDistinctR( state ) },<br />
anything updated: { useAnythingUpdating( state ) },<br />
// ...
const useAnythingUpdating = function(state){
const [result, setResult ] = useState(0);
useEffect(() => {
setResult( state );
console.log('anything updated');
});
return result;
};
*但你不应该依赖其他触发重新渲染的东西。我什至不确定这会在所有情况下按预期更新。
更多细节:
useEffect()
prop
在 react 决定必须更改时触发。然后ref
更改了,但是 react 不会“得到通知”有关ref
更改,因此它认为没有必要重新渲染页面以显示更改的值。
在没有useEffect()
变化的例子中是同步发生的。React 也不“知道”这种变化,但是(如果其他一切都按预期运行)无论如何都会在必要时重新渲染(您将在最后渲染的另一个函数中调用该函数)。
(不通知 react 变化基本上是使用的重点useRef()
:有时你只需要一个值,在你自己的控制下,而不用 react 用它做魔法。)
推荐阅读
- python - Auto_arima 参数选择
- spring - 自动装配 HibernateTemplate 时不创建 Bean
- python-3.x - ValueError:无法将大小为 13 的序列复制到维度为 200 的数组轴
- django - auto_now_add 在 Django 单元测试中创建 NotNullViolation
- r - 如果按下按钮或从 DT 中选择行,则 Rshiny 条件按钮/div/表格
- reactjs - 如何将 react-share 与 Material UI 的 SpeedDial 一起使用?
- apache-spark - 访问 spark keyvaluegroupeddataset 中的每个组
- css - Flask,CSS文件未在路线上注册
- python - 按相关字段值分组查询集
- javascript - NPM:找不到模块'../lib/utils/unsupported.js'