Reactjs 使用数组对useState作出反应
在react中,将状态的值设置为相等的旧值保证不会触发渲染,对吗 将数组存储为状态如何?Reactjs 使用数组对useState作出反应,reactjs,react-hooks,Reactjs,React Hooks,在react中,将状态的值设置为相等的旧值保证不会触发渲染,对吗 将数组存储为状态如何? React通过引用而不是值来比较数组。 因此,使用完全相同的值设置新数组仍会触发渲染 我创建了一个组件,用于监听滚动事件 因此,我需要使用useffect来附加和分离滚动事件 在每个滚动事件中,它确定哪些子项在滚动视图中可见, 并将子对象的索引(一个索引数组)保存到一个状态中,如下所示: const [index, setIndex] = useState(-1); const [indices,
React通过引用而不是值来比较数组。 因此,使用完全相同的值设置新数组仍会触发渲染 我创建了一个组件,用于监听滚动事件
因此,我需要使用
useffect
来附加和分离滚动事件
在每个滚动事件中,它确定哪些子项在滚动视图中可见,并将子对象的索引(一个索引数组)保存到一个状态中,如下所示:
const [index, setIndex] = useState(-1);
const [indices, setIndices] = useState([]);
/* ... */
useEffect(() => {
const handleScroll = () => {
const newIndex : number = calculateFirstVisibleChild();
const newIndices: number[] = calculateVisibleChildren();
// save the result:
setIndex(newIndex); // trigger render only if the value changes (works)
setIndices(newIndices); // always trigger render (works but inefficient)
}
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll); // cleanup
}, []); // no dep, execute once at startup
问题是:如何在不触发渲染的情况下设置具有相同值的索引
如果滚动距离很小,则可见子对象保持不变,因此函数仍返回相同的值 在传递到
setIndexs
之前,我无法比较索引
和新索引
,因为它需要列在useEffect的依赖项上,从而导致事件侦听器在每次索引/索引更改时都不必要地分离和附加回去
下面是我试图制作的组件的屏幕截图:
更新:这里是存储的索引的用法
/索引
:
此时,我使用索引(单级)。
在索引
问题解决后,我将把我的导航滚动
升级到多级
// the render:
.....map((child, i) => (
<ListGroupItem
key={i}
active={(i === index)} // here the actual highlight works! true: highlight, false: normal
>
</ListGroupItem>
.....
//渲染:
…映射((子,i)=>(
.....
更新:
我将把索引数组转换为逗号分隔字符串,以避免触发不必要的渲染,并在渲染时解析/转换回数组。
我知道这是一个丑陋的黑客,但它是有效的。
请帮我用漂亮的方法解决。我假设CalculateVibleChildren()
返回一个数组,对吗?如果是这样,那么NewIndexes
本质上是一个新数组,即使所有元素都相同。因此react将重新渲染
但是,我假设您将以这种方式使用索引
// render
return (
<div>
{indices.map(index => <SomeComponent index={index} />)}
</div>
);
有关更多信息,请参阅about备忘录。在我花了一天时间搜索解决方案后,
我发现了一个useReducer
hook。对我来说,它是useState
的高级版本
getter仍然与useState
相同,但setter具有更多的控制权(cmiiw)
//const[activeindex,setactiveindex]=useState([]);//再见
const[activeindex,setactiveindex]=useReducer((索引:number[],新索引:number[]):number[]=>{
如果(deepEqual(newindex,index))返回索引;//已经相同,请通过引用使用旧的as
return newindex;//使用新索引更新
}, []);
只需创建两个效果。一个用于在组件装载/卸载时附加/分离事件侦听器,另一个用于跟踪状态变量的更改。
// SomeComponent.js
import { memo } from "react";
const SomeComponent = () => {
return /* some components */;
}
export default memo(SomeComponent);
// const [activeIndices, setActiveIndices] = useState<number[]>([]); // bye-bye
const [activeIndices, setActiveIndices] = useReducer((indices: number[], newIndices: number[]): number[] => {
if (deepEqual(newIndices, indices)) return indices; // already the same, use the old as by-reference
return newIndices; // update with the new one
}, []);