有一个容器ul
保持在一个设定的高度,因此当ul
中的内容溢出时,它应该从列表中删除第一个项目。每个列表项目显示为一个搜索结果,ul
在不溢出的情况下只能容纳6个结果。该列表应该使用setRecent
进行更改,因为它是使用useState
声明的。但是当我尝试通过使用[...list].splice(1)
删除第一个项目来更改列表时,它返回以下错误:
超出了最大更新深度。当组件在componentWillUpdate或componentDidUpdate内重复调用setState时,可能会发生这种情况。React限制嵌套更新的数量以防止无限循环。
当我删除setRecent
并只返回值[...list].splice(1)
时,它返回的列表没有第一项,但是需要setRecent
来更改列表的值。
我该怎么解决这个问题?
const [recent, setRecent] = useState(["Dubai", "Paris", "London", "paris", "new york", "dubai", "New York"]);
const InsideSection = () => {
const ulRef = createRef();
useLayoutEffect(() => {
if (onSearch) {
const element = ulRef.current;
if (element.scrollHeight > element.clientHeight) { // checks for overflow
console.log("overflow");
console.log(recent, "before"); // returns [] instead of the list
console.log([...recent].slice(1));
// this should return ["Paris", "London", "paris", "new york", "dubai", "New York"] (without the first "Dubai")
// but when there is a setRecent inside the if statement, it causes an error as recent is []
setRecent([...recent].slice(1)); // causes the error
console.log(recent, "after"); // returns []
}
}
}, [ulRef]);
if (onSearch) {
return (
<div className = "search-container" >
...
<ul ref = {ulRef} >
<RecentSearches />
</ul>
</div >
);
}
}
2条答案
按热度按时间5ktev3wc1#
您的问题是在父组件内定义InsideSection组件。从InsideSection调用父组件的setRecent状态处理程序时,将导致重新呈现,从而导致再次执行父组件并重新创建InsideSection组件。这将再次触发useLayoutEffect。useLayoutEffect重新更新父对象的状态,父对象重新呈现并重新创建InsideSection,InsideSection一次又一次地重新触发useLayoutEffect。
每一次,它都会将你最近的数组从[“迪拜”、“巴黎”、“伦敦”、“巴黎”、“纽约”、“迪拜”、“纽约”]切片到[“巴黎”、“伦敦”、“巴黎”、“纽约”、“迪拜”、“纽约”]再到[“伦敦”、“巴黎”、“纽约”、“迪拜”,“纽约”]等等,直到它是[]并且不能再切片(这是它抛出错误的地方)。
解决方案是将InsideSection组件移出父组件,如果最近使用的变量仅由InsideSection组件使用,则在父组件中而不是父组件中定义它。如果最近使用的变量需要由父组件和子组件使用,则“不太”干净的解决方案是将其作为prop传递。
可能的解决方案如下所示:
另一个解决方案是使用Context,我给你留了文档:https://reactjs.org/docs/context.html
PS:代码可能需要一些调整,这只是一个例子
hvvq6cgz2#
它并不完美,但如果您使用带有ref和超时的去抖策略,它就可以发挥作用:
https://codesandbox.io/s/pensive-gould-4bmhns?file=/src/App.js