Reactjs 使用数组对useState作出反应

Reactjs 使用数组对useState作出反应,reactjs,react-hooks,Reactjs,React Hooks,在react中,将状态的值设置为相等的旧值保证不会触发渲染,对吗 将数组存储为状态如何? React通过引用而不是值来比较数组。 因此,使用完全相同的值设置新数组仍会触发渲染 我创建了一个组件,用于监听滚动事件 因此,我需要使用useffect来附加和分离滚动事件 在每个滚动事件中,它确定哪些子项在滚动视图中可见, 并将子对象的索引(一个索引数组)保存到一个状态中,如下所示: const [index, setIndex] = useState(-1); const [indices,

在react中,将状态的值设置为相等的旧值保证不会触发渲染,对吗

将数组存储为状态如何?
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
    }, []);