如何将 React Signals 与数组一起使用?

问题描述 投票:0回答:1

我正在尝试使用信号(

@preact/signals-react
)来减少大型数据对象的重新渲染。就我而言,我从网络请求中获取对象,并且往往会随着实时更新而频繁更改。

对于直接属性,效果很好,减少了重新渲染的次数:

export function Root(){
  const mySignal = useSignal({ sub: { val: 1 }, arr: [{id: 1, name: "bob"}] });

  return <div>
    <Counter signal={mySignal} /> 
    <Array signal={mySignal} /> 
  </div>
}

function Counter({ signal }) {
  const counter = useComputed(() => signal.value.counter);

  return (
    <div>
      <p>{counter}</p>
      <button
        onClick={() => {
          signal.value = { ...signal.value, counter: signal.value.counter + 1 };
        }}
      >
        Increment
      </button>
    </div>
  );
}

在这种情况下,只有

Counter
在递增 👌 时重新渲染。
当我们有
useSignals()
时也是如此。

但是,对于数组,情况有所不同:

function ArrayConsumer({ mySignal }: { mySignal: MySignal }) {
  const arr = useComputed(() => mySignal.value.someArr);

  return (
    <>
      {arr.value.map((item) => (
        // renders and edits {item.name}
        <ArrayItem key={item.id} item={item} />
      ))}
    </>
  );
}

因为我直接使用 arr.value,所以每当数组更改时,整个列表都会重新渲染。 我期望某种

signalMap()
方法,但 docs 仅建议在那里使用 signal.value 。

一种解决方案是将各个列表项包装在信号中,但这似乎是一种不好的做法?我真的认为信号可以提供与 Mobx 相似的性能和 devexp,但如果没有列表支持,它的用处就小得多。

javascript reactjs preact-signal
1个回答
0
投票

该库旨在成为一组核心原语,因此不涉及可以从用户空间添加的实用程序。这些东西很容易自己构建。这是 Jason/developit 不久前编写的一个有用的实用程序:

const Item = ({ v, k, f }) => f(v, k); /** * Like signal.value.map(fn), but doesn't re-render. */ export function For({ each, children: f, fallback }) { let c = useMemo(() => new Map(), []); return ( each.value?.map( (v, k, x) => c.get(v) || (c.set(v, (x = <Item {...{ key: v, v, k, f }} />)), x) ) ?? fallback ); }
现在,对于您的示例,您可以像这样使用它:

function ArrayConsumer({ mySignal }: { mySignal: MySignal }) { const arr = useComputed(() => mySignal.value.someArr); return ( <> <For each={arr} children={(item) => ( <ArrayItem key={item.id} item={item} /> )} /> </> ); }
    
© www.soinside.com 2019 - 2024. All rights reserved.