rwi*_*ang 77 reactjs react-hooks
假设我有3个输入:rate,sendAmount和receiveAmount.我把3个输入放在useEffect diffing params上.规则是:
receiveAmount = sendAmount * ratesendAmount = receiveAmount / ratereceiveAmount = sendAmount * rate何时sendAmount > 0或我计算sendAmount = receiveAmount / rate何时receiveAmount > 0这是代码框https://codesandbox.io/s/pkl6vn7x6j来演示这个问题.
有没有办法比较oldValues和newValues喜欢,componentDidUpdate而不是为这种情况下制作3个处理程序?
谢谢
这是我的最终解决方案usePrevious
https://codesandbox.io/s/30n01w2r06
在这种情况下,我不能使用多个useEffect因为每个更改导致相同的网络调用.这也是我也用它changeCount来跟踪变化的原因.这changeCount也有助于跟踪仅来自本地的更改,因此我可以防止因服务器更改而进行不必要的网络调用.
Shu*_*tri 107
你可以编写一个自定义钩子,使用useRef为你提供以前的道具
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
Run Code Online (Sandbox Code Playgroud)
然后使用它 useEffect
const Component = (props) => {
const {receiveAmount, sendAmount } = props
const prevAmount = usePrevious({receiveAmount, sendAmount});
useEffect(() => {
if(prevAmount.receiveAmount !== receiveAmount) {
// process here
}
if(prevAmount.sendAmount !== sendAmount) {
// process here
}
}, [receiveAmount, sendAmount])
}
Run Code Online (Sandbox Code Playgroud)
然而,如果您useEffect为每个更改ID单独使用两个,则它更清晰,可能更好,更清晰,您可以单独处理它们
Dra*_*vuk 18
离开接受的答案,一个不需要自定义钩子的替代解决方案:
const Component = ({ receiveAmount, sendAmount }) => {
const prevAmount = useRef({ receiveAmount, sendAmount }).current;
useEffect(() => {
if (prevAmount.receiveAmount !== receiveAmount) {
// process here
}
if (prevAmount.sendAmount !== sendAmount) {
// process here
}
return () => {
prevAmount.receiveAmount = receiveAmount;
prevAmount.sendAmount = sendAmount;
};
}, [receiveAmount, sendAmount]);
};
Run Code Online (Sandbox Code Playgroud)
这假设您实际上需要引用“此处处理”位中任何内容的先前值。否则,除非您的条件超出了直接!==比较的范围,否则这里最简单的解决方案就是:
const Component = ({ receiveAmount, sendAmount }) => {
useEffect(() => {
// process here
}, [receiveAmount]);
useEffect(() => {
// process here
}, [sendAmount]);
};
Run Code Online (Sandbox Code Playgroud)
See*_*ROM 13
如果有人正在寻找use的TypeScript版本
import { useEffect, useRef } from "react";
const usePrevious = <T extends {}>(value: T) => {
const ref = useRef<T>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
Run Code Online (Sandbox Code Playgroud)
Ben*_*arp 12
将当前值与先前值进行比较是一种常见的模式,它证明了自己的自定义钩子是正确的,从而隐藏了实现细节。
const useCompare = (val: any) => {
const prevVal = usePrevious(val)
return prevVal !== val
}
const usePrevious = (value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const Component = (props) => {
...
const hasVal1Changed = useCompare(val1)
const hasVal2Changed = useCompare(val2);
useEffect(() => {
if (hasVal1Changed ) {
console.log("val1 has changed");
}
if (hasVal2Changed ) {
console.log("val2 has changed");
}
});
return <div>...</div>;
};
Run Code Online (Sandbox Code Playgroud)
const Component = (props) => {
...
useEffect(() => {
console.log("val1 has changed");
}, [val1]);
useEffect(() => {
console.log("val2 has changed");
}, [val2]);
return <div>...</div>;
};
Run Code Online (Sandbox Code Playgroud)
我刚刚发布了react-delta解决了这种确切的场景。在我看来,useEffect有太多的责任。
Object.isreact-delta将useEffect的职责分解为几个较小的钩子。
责任#1
usePrevious(value)useLatest(value)useDelta(value, options)useDeltaArray(valueArray, options)useDeltaObject(valueObject, options)some(deltaArray)every(deltaArray)责任#2
根据我的经验,这种方法比useEffect/useRef解决方案更灵活、干净和简洁。
这是我使用的一个自定义钩子,我认为它比使用usePrevious.
import { useRef, useEffect } from 'react'
// useTransition :: Array a => (a -> Void, a) -> Void
// |_______| |
// | |
// callback deps
//
// The useTransition hook is similar to the useEffect hook. It requires
// a callback function and an array of dependencies. Unlike the useEffect
// hook, the callback function is only called when the dependencies change.
// Hence, it's not called when the component mounts because there is no change
// in the dependencies. The callback function is supplied the previous array of
// dependencies which it can use to perform transition-based effects.
const useTransition = (callback, deps) => {
const func = useRef(null)
useEffect(() => {
func.current = callback
}, [callback])
const args = useRef(null)
useEffect(() => {
if (args.current !== null) func.current(...args.current)
args.current = deps
}, deps)
}
Run Code Online (Sandbox Code Playgroud)
您可以按如下方式使用useTransition。
useTransition((prevRate, prevSendAmount, prevReceiveAmount) => {
if (sendAmount !== prevSendAmount || rate !== prevRate && sendAmount > 0) {
const newReceiveAmount = sendAmount * rate
// do something
} else {
const newSendAmount = receiveAmount / rate
// do something
}
}, [rate, sendAmount, receiveAmount])
Run Code Online (Sandbox Code Playgroud)
希望有帮助。
由于状态与功能组件中的组件实例并不紧密耦合,因此如果不先保存之前的状态(useEffect例如,使用useRef. 这也意味着状态更新可能在错误的位置错误地实现,因为先前的状态在更新器函数中可用setState。
这是一个很好的用例,useReducer它提供了类似 Redux 的存储并允许实现相应的模式。状态更新是显式执行的,因此无需弄清楚更新了哪个状态属性;从派遣行动中已经可以清楚地看出这一点。
下面是一个示例:
function reducer({ sendAmount, receiveAmount, rate }, action) {
switch (action.type) {
case "sendAmount":
sendAmount = action.payload;
return {
sendAmount,
receiveAmount: sendAmount * rate,
rate
};
case "receiveAmount":
receiveAmount = action.payload;
return {
sendAmount: receiveAmount / rate,
receiveAmount,
rate
};
case "rate":
rate = action.payload;
return {
sendAmount: receiveAmount ? receiveAmount / rate : sendAmount,
receiveAmount: sendAmount ? sendAmount * rate : receiveAmount,
rate
};
default:
throw new Error();
}
}
function handleChange(e) {
const { name, value } = e.target;
dispatch({
type: name,
payload: value
});
}
...
const [state, dispatch] = useReducer(reducer, {
rate: 2,
sendAmount: 0,
receiveAmount: 0
});
...
Run Code Online (Sandbox Code Playgroud)
如果您更喜欢useEffect替换方法:
const usePreviousEffect = (fn, inputs = []) => {
const previousInputsRef = useRef([...inputs])
useEffect(() => {
fn(previousInputsRef.current)
previousInputsRef.current = [...inputs]
}, inputs)
}
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
usePreviousEffect(
([prevReceiveAmount, prevSendAmount]) => {
if (prevReceiveAmount !== receiveAmount) // side effect here
if (prevSendAmount !== sendAmount) // side effect here
},
[receiveAmount, sendAmount]
)
Run Code Online (Sandbox Code Playgroud)
请注意,第一次执行效果时,传递给您的先前值fn将与您的初始输入值相同。这只会事给你,如果你想要做的东西,当值没有改变。
| 归档时间: |
|
| 查看次数: |
42376 次 |
| 最近记录: |