Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs 从特定函数更新状态时防止useEffect重新触发_Reactjs_React Hooks - Fatal编程技术网

Reactjs 从特定函数更新状态时防止useEffect重新触发

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]

我有以下组件:

从“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不需要


如果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']。