Javascript 确定引发useEffect挂钩的依赖项数组变量
是否有一种简单的方法来确定Javascript 确定引发useEffect挂钩的依赖项数组变量,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,是否有一种简单的方法来确定useffect的依赖项数组中的哪个变量触发函数重新激发 如果a是一个函数,而b是一个对象,那么简单地注销每个变量可能会产生误导,它们在记录时可能看起来相同,但实际上不同,并导致useEffect火灾 例如: React.useEffect(() => { // which variable triggered this re-fire? console.log('---useEffect---') }, [a, b, c, d]) 我当前的方法是逐个删
useffect
的依赖项数组中的哪个变量触发函数重新激发
如果a
是一个函数,而b
是一个对象,那么简单地注销每个变量可能会产生误导,它们在记录时可能看起来相同,但实际上不同,并导致useEffect火灾
例如:
React.useEffect(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d])
我当前的方法是逐个删除依赖变量,直到我注意到导致过多useEffect调用的行为,但必须有更好的方法来缩小范围。更新 在经过一点实际使用后,到目前为止,我喜欢以下借鉴了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
};
然后,可以通过复制依赖项数组文本并将其更改为对象文本来使用该属性:
useDependenciesDebugger({ state1, state2 });
这允许日志记录知道变量的名称,而无需为此目的使用任何单独的参数
据我所知,没有现成的简单方法可以做到这一点,但您可以插入一个自定义挂钩,它可以跟踪其依赖项并记录更改的内容:
// 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);
};
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)
}
})
}
useEffectDebugger(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d], 'Effect Name')
您可以这样使用:
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)
}
})
}
useEffectDebugger(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d], 'Effect Name')
您将得到如下输出:
Effect Name - The input changed in position 2
Old value: "Previous value"
New value: "New value"
还有另一个堆栈溢出线程声明可以使用useRef查看以前的值
最后,我从各种答案中提取了一点,为这个问题制作了自己的钩子。我希望能够删除一些东西来代替
useffect
,以便快速调试触发useffect
的依赖项
const usePrevious = (value, initialValue) => {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
};
下面是两个例子。对于每个示例,我假设dep2
从'foo'更改为'bar'。示例1显示了不传递dependencyNames
的输出,示例2显示了带有dependencyNames
的示例
示例1
之前:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
之后:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2])
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2], ['dep1', 'dep2'])
控制台输出:
{
1: {
before: 'foo',
after: 'bar'
}
}
{
dep2: {
before: 'foo',
after: 'bar'
}
}
对象键“1”表示已更改的依赖项的索引。此处,dep1
已更改,是依赖项或索引1中的第二项
示例2
之前:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
之后:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2])
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2], ['dep1', 'dep2'])
控制台输出:
{
1: {
before: 'foo',
after: 'bar'
}
}
{
dep2: {
before: 'foo',
after: 'bar'
}
}
这个图书馆
,就像一个符咒!
使用npm/warn
和--dev
或--no save
//像这样使用:
导出函数App(){
返回{
const[someData,setSomeData]=useState()
useffect(()=>{
window.fetch(fetchOptions).then((数据)=>{
setSomeData(数据)
})
},[fetchOptions])
返回hello{someData.firstName}
}
如果可以,对象情况下的修复将在组件渲染外部打断静态对象:
const fetchSomeDataOptions = {
urlThing: '/foo',
headerThing: 'FOO-BAR'
}
export function App() {
return <MyComponent fetchOptions={fetchSomeDataOptions} />
}
const fetchSomeDataOptions={
urlshing:“/foo”,
标题:“FOO-BAR”
}
导出函数App(){
返回
}
您还可以在UseMoom中换行:
export function App() {
return <MyComponent fetchOptions={
useMemo(
() => {
return {
urlThing: '/foo',
headerThing: 'FOO-BAR',
variableThing: hash(someTimestamp)
}
},
[hash, someTimestamp]
)
} />
}
导出函数App(){
返回{
返回{
urlshing:“/foo”,
标题:“FOO-BAR”,
变量:散列(someTimestamp)
}
},
[哈希,时间戳]
)
} />
}
同样的概念在某种程度上也适用于函数,但最终可能会导致过时的闭包。我也喜欢这个答案。与我的答案相比,设置它需要做更多的工作,但会提供更好的输出,因为每个依赖项都有一个名称,而我的只说明更改了哪个索引。您可以从包含
true
和false
的引用切换到包含null
和{prevValue:value}的引用
如果您想在旧值和新值发生变化时记录它们。发布到其他StackOverflow线程的链接可能会很有用。您应该将此发布到NPM!这太棒了。(点表示一个值没有改变。绿色的复选框表示它确实改变了。)甚至还有一个巴贝尔插件(真的去启动这个家伙的项目!)idk为什么,但它没有记录任何东西me@JamilAlisgenderov我认为useWhatChanged必须使用console.table。。因此,如果您试图在不支持console.table的旧浏览器中进行测试,则可以检查是否定义了console.table。您还可以验证正常的console.log('something changed'、'table defined?'、!!console.table);在useEffect钩子日志中。否则。。。可能在github上用您的react版本提交一个问题+browser@JamilAlisgenderov有没有弄清楚是什么原因导致使用什么更改为不为您记录任何内容?