Reactjs 从特定函数更新状态时防止useEffect重新触发
我有以下组件: 从“React”导入React,{useffect,useState}; 常量输入==>{ const[name,setName]=useState; 回来 setNamee.target.value} 值={name}> ; } 导出默认输入; 该组件是一个缓冲区,存储每次更改时的输入值,允许执行撤消操作 const Undo={name,setName}=>{ const[buffer,setBuffer]=useState[,]; const[index,setIndex]=useState-1; useEffect=>{ 让copy=[…缓冲区,名称].slice-3; 设pos=index+1; ifpos>2 pos=2; 立位镜检; setIndexpos; },[姓名]; 常量撤消==>{ 设pos=index-1; ifpos<0 pos=-1; setNamebuffer[pos]; setIndexpos; } 回来 打开 ; } 例如: 如果用户在输入上键入'abc',则缓冲区=['a','ab','abc'],索引=2 当用户单击按钮时,组件应返回到以前的状态。也就是说,buffer=['a','ab','abc']和index=1 点击按钮后,执行setNamebuffer[pos],再次触发useEffect:buffer=['ab','abc','ab']和index=2不需要Reactjs 从特定函数更新状态时防止useEffect重新触发,reactjs,react-hooks,Reactjs,React Hooks,我有以下组件: 从“React”导入React,{useffect,useState}; 常量输入==>{ const[name,setName]=useState; 回来 setNamee.target.value} 值={name}> ; } 导出默认输入; 该组件是一个缓冲区,存储每次更改时的输入值,允许执行撤消操作 const Undo={name,setName}=>{ const[buffer,setBuffer]=useState[,]; const[index,setIndex]
如果useEffect钩子被撤销功能重新触发,我如何防止它重新触发?我不会为此使用useEffect。我的拙见是,您的撤销缓冲区不是DOM意义上的副作用,而是您希望应用于状态更改的内部逻辑。类似地,您的撤销组件是一个按钮,它也恰好具有关于历史和状态的可重用逻辑,可以说它更属于父级而不是按钮本身 总的来说,我认为这种方法并不是一种干净的自上而下的流程,而且在React中往往会导致此类问题 相反,我会先将撤消逻辑和状态放入父级:
const handleChange = function(e){
// add to undo buffer here
setName(e.target.value);
}
const handleUndo = function(){
// fetch your undo buffer here
setName(undoValue);
}
onChange = {handleChange}
onClick = {handleUndo}
在连接完所有内容后,您可能会觉得这样做会使撤消组件失去干净的可重用性,您是对的。但这正是它们的用途:可重用的有状态逻辑。有很多方法可以实现这一点,但下面是一个定制钩子的示例,您可以编写:
const [name, setName, undoName] = useUndoableState('');
钩子将替换useState并在钩子内部使用它自己,管理缓冲区,并提供一个额外的函数来调用undo,该函数将倒带并设置新名称
<input onChange={setName} />
<button onClick={undoName}>Undo</button>
我不会用useEffect来做这个。我的拙见是,您的撤销缓冲区不是DOM意义上的副作用,而是您希望应用于状态更改的内部逻辑。类似地,您的撤销组件是一个按钮,它也恰好具有关于历史和状态的可重用逻辑,可以说它更属于父级而不是按钮本身 总的来说,我认为这种方法并不是一种干净的自上而下的流程,而且在React中往往会导致此类问题 相反,我会先将撤消逻辑和状态放入父级:
const handleChange = function(e){
// add to undo buffer here
setName(e.target.value);
}
const handleUndo = function(){
// fetch your undo buffer here
setName(undoValue);
}
onChange = {handleChange}
onClick = {handleUndo}
在连接完所有内容后,您可能会觉得这样做会使撤消组件失去干净的可重用性,您是对的。但这正是它们的用途:可重用的有状态逻辑。有很多方法可以实现这一点,但下面是一个定制钩子的示例,您可以编写:
const [name, setName, undoName] = useUndoableState('');
钩子将替换useState并在钩子内部使用它自己,管理缓冲区,并提供一个额外的函数来调用undo,该函数将倒带并设置新名称
<input onChange={setName} />
<button onClick={undoName}>Undo</button>
我认为您的问题在于逻辑本身,而不是名称更改时重新触发的useEffect。如果我理解正确,您希望您的撤消按钮只更改索引而不修改缓冲区,对吗?是的,对。撤消按钮:更改索引,而不是修改缓冲区和更新名称变量。请记住,我只能控制“Undo”组件,因此我无法在主组件上设置缓冲区和索引。假设缓冲区=['a'、'ab'、'abc'],如果按两次Undo,您希望使用“abc”还是“a”?是否可以选择放弃组件方法,只使用自定义挂钩useUndoableState?假设缓冲区=['a','ab','abc'],通过按两次undo,我希望输入上有'a',index=0和buffer=['a','ab','abc']。我认为您的问题在于逻辑本身,而不是名称更改时的useEffect重新触发。如果我理解正确,您希望您的撤消按钮仅更改索引而不修改缓冲区,对吗?是的,对。撤消按钮:更改索引,而不是修改缓冲区并更新名称变量。请记住,我只有控制权l覆盖“Undo”组件,因此我无法在主组件上设置缓冲区和索引。假设缓冲区=['a','ab','abc',],如果按两次Undo,您会
nt是否有“abc”或“a”?是否可以选择放弃组件方法,只使用自定义钩子useUndoableState?假设buffer=['a'、'ab'、'abc'],按两次undo,我希望输入上有“a”,index=0,buffer=['a'、'ab'、'abc']。