Cum*_*bus 12 javascript reactjs react-hooks
有没有一种简单的方法来确定useEffectDependency数组中的哪个变量触发函数重新触发?
简单地注销每个变量可能会产生误导,如果a是函数和b对象,则它们在登录时可能看起来相同,但实际上却有所不同,从而引起useEffect触发。
例如:
React.useEffect(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d])
Run Code Online (Sandbox Code Playgroud)
我当前的方法一直是一个一个地删除依赖变量,直到我注意到导致过多useEffect调用的行为,但是必须有一种更好的方法来缩小此范围。
Bra*_*yan 82
我最终从各种答案中汲取了一点点来制作自己的钩子。我希望能够直接删除一些东西useEffect来快速调试正在触发的依赖项useEffect。
const usePrevious = (value, initialValue) => {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
};
Run Code Online (Sandbox Code Playgroud)
const useEffectDebugger = (effectHook, dependencies, dependencyNames = []) => {
const previousDeps = usePrevious(dependencies, []);
const changedDeps = dependencies.reduce((accum, dependency, index) => {
if (dependency !== previousDeps[index]) {
const keyName = dependencyNames[index] || index;
return {
...accum,
[keyName]: {
before: previousDeps[index],
after: dependency
}
};
}
return accum;
}, {});
if (Object.keys(changedDeps).length) {
console.log('[use-effect-debugger] ', changedDeps);
}
useEffect(effectHook, dependencies);
};
Run Code Online (Sandbox Code Playgroud)
下面是两个例子。对于每个示例,我假设dep2从“foo”更改为“bar”。示例 1 显示了未通过的输出dependencyNames,示例 2 显示了带有 dependencyNames.
示例 1
前:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
Run Code Online (Sandbox Code Playgroud)
后:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2])
Run Code Online (Sandbox Code Playgroud)
控制台输出:
{
1: {
before: 'foo',
after: 'bar'
}
}
Run Code Online (Sandbox Code Playgroud)
对象键“1”表示更改的依赖项的索引。在这里,已dep1更改并且是依赖项中的第二项,或索引 1
示例 2
前:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
Run Code Online (Sandbox Code Playgroud)
后:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2], ['dep1', 'dep2'])
Run Code Online (Sandbox Code Playgroud)
控制台输出:
{
dep2: {
before: 'foo',
after: 'bar'
}
}
Run Code Online (Sandbox Code Playgroud)
Dev*_*ode 25
@simbathesailor/use-what-changed Install与npm/yarn和--dev或--no-saveimport { useWhatChanged } from '@simbathesailor/use-what-changed';
Run Code Online (Sandbox Code Playgroud)
// (guarantee useEffect deps are in sync with useWhatChanged)
let deps = [a, b, c, d]
useWhatChanged(deps, 'a, b, c, d');
useEffect(() => {
// your effect
}, deps);
Run Code Online (Sandbox Code Playgroud)
在控制台中创建这个漂亮的图表:
有两个常见的罪魁祸首:
// Being used like:
export function App() {
return <MyComponent fetchOptions={{
urlThing: '/foo',
headerThing: 'FOO-BAR'
})
}
export const MyComponent = ({fetchOptions}) => {
const [someData, setSomeData] = useState()
useEffect(() => {
window.fetch(fetchOptions).then((data) => {
setSomeData(data)
})
}, [fetchOptions])
return <div>hello {someData.firstName}</div>
}
Run Code Online (Sandbox Code Playgroud)
在对象情况下的修复,如果可以的话,在组件渲染之外打破一个静态对象:
const fetchSomeDataOptions = {
urlThing: '/foo',
headerThing: 'FOO-BAR'
}
export function App() {
return <MyComponent fetchOptions={fetchSomeDataOptions} />
}
Run Code Online (Sandbox Code Playgroud)
你也可以用 useMemo 包装:
export function App() {
return <MyComponent fetchOptions={
useMemo(
() => {
return {
urlThing: '/foo',
headerThing: 'FOO-BAR',
variableThing: hash(someTimestamp)
}
},
[hash, someTimestamp]
)
} />
}
Run Code Online (Sandbox Code Playgroud)
相同的概念在一定程度上适用于函数,除非您最终会得到陈旧的闭包。
更新
经过一些实际使用后,到目前为止,我喜欢以下解决方案,它借鉴了 Retsam 解决方案的某些方面:
const compareInputs = (inputKeys, oldInputs, newInputs) => {
inputKeys.forEach(key => {
const oldInput = oldInputs[key];
const newInput = newInputs[key];
if (oldInput !== newInput) {
console.log("change detected", key, "old:", oldInput, "new:", newInput);
}
});
};
const useDependenciesDebugger = inputs => {
const oldInputsRef = useRef(inputs);
const inputValuesArray = Object.values(inputs);
const inputKeysArray = Object.keys(inputs);
useMemo(() => {
const oldInputs = oldInputsRef.current;
compareInputs(inputKeysArray, oldInputs, inputs);
oldInputsRef.current = inputs;
}, inputValuesArray); // eslint-disable-line react-hooks/exhaustive-deps
};
Run Code Online (Sandbox Code Playgroud)
然后可以通过复制依赖数组文字并将其更改为对象文字来使用它:
useDependenciesDebugger({ state1, state2 });
Run Code Online (Sandbox Code Playgroud)
这允许日志记录知道变量的名称,而无需为此目的提供任何单独的参数。
据我所知,开箱即用并没有真正简单的方法可以做到这一点,但是您可以放入一个自定义钩子来跟踪其依赖项并记录哪个更改了:
// Same arguments as useEffect, but with an optional string for logging purposes
const useEffectDebugger = (func, inputs, prefix = "useEffect") => {
// Using a ref to hold the inputs from the previous run (or same run for initial run
const oldInputsRef = useRef(inputs);
useEffect(() => {
// Get the old inputs
const oldInputs = oldInputsRef.current;
// Compare the old inputs to the current inputs
compareInputs(oldInputs, inputs, prefix)
// Save the current inputs
oldInputsRef.current = inputs;
// Execute wrapped effect
func()
}, inputs);
};
Run Code Online (Sandbox Code Playgroud)
该compareInputs位可能如下所示:
const compareInputs = (oldInputs, newInputs, prefix) => {
// Edge-case: different array lengths
if(oldInputs.length !== newInputs.length) {
// Not helpful to compare item by item, so just output the whole array
console.log(`${prefix} - Inputs have a different length`, oldInputs, newInputs)
console.log("Old inputs:", oldInputs)
console.log("New inputs:", newInputs)
return;
}
// Compare individual items
oldInputs.forEach((oldInput, index) => {
const newInput = newInputs[index];
if(oldInput !== newInput) {
console.log(`${prefix} - The input changed in position ${index}`);
console.log("Old value:", oldInput)
console.log("New value:", newInput)
}
})
}
Run Code Online (Sandbox Code Playgroud)
你可以这样使用它:
useEffectDebugger(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d], 'Effect Name')
Run Code Online (Sandbox Code Playgroud)
你会得到如下输出:
Effect Name - The input changed in position 2
Old value: "Previous value"
New value: "New value"
Run Code Online (Sandbox Code Playgroud)
还有\xe2\x80\x99s 另一个堆栈溢出线程,声明您可以使用 useRef 来查看以前的值。
\n\nhttps://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
\n| 归档时间: |
|
| 查看次数: |
870 次 |
| 最近记录: |