为何@legendapp/state的<Computed>组件状态变化时不重渲染?
Legend State中Computed组件不随Observable状态更新重渲染的问题
我在探索Legend State时遇到一个问题:当Observable状态变化时,<Computed>组件不会触发重渲染,但<Show>组件能正常工作。
预期效果是每秒切换showChild状态,状态变化后<Show>组件正常重渲染,但<Computed>组件没有反应。
我的代码如下:
import {Computed, Show, useObservable} from '@legendapp/state/react' import { useInterval } from '../utils/hooks' function LegendStateModal() { const showChild = useObservable(false) // const text = useComputed(() => showChild.get() ? 'true' : 'false') useInterval(() => { showChild.set((v) => !v) }, 1000) return ( <div className='flex flex-col'> <span>Showing child: </span> <Computed> <span className={showChild.get() ? 'text-red-900' : 'text-green-900'} > {showChild.get() ? 'true' : 'false'} </span> </Computed> <Show if={showChild}> <div>Child element</div> </Show> </div> ) } export default LegendStateModal;
问题原因
<Computed>组件的核心是依赖追踪,它需要接收一个函数作为子元素,通过函数内部对Observable状态的访问来建立依赖关系。你当前的写法是直接在<Computed>中嵌套JSX,内部的showChild.get()调用无法被Legend State的依赖系统捕获,因此状态变化时不会触发重渲染。
而<Show>组件内部已经封装了完整的依赖追踪逻辑,直接传入Observable就能自动响应状态变化。
解决方案
方案1:给Computed传递函数子元素
这是<Computed>组件的标准用法,将JSX包裹在函数中传入:
import {Computed, Show, useObservable} from '@legendapp/state/react' import { useInterval } from '../utils/hooks' function LegendStateModal() { const showChild = useObservable(false) useInterval(() => { showChild.set((v) => !v) }, 1000) return ( <div className='flex flex-col'> <span>Showing child: </span> <Computed> {() => ( <span className={showChild.get() ? 'text-red-900' : 'text-green-900'} > {showChild.get() ? 'true' : 'false'} </span> )} </Computed> <Show if={showChild}> <div>Child element</div> </Show> </div> ) } export default LegendStateModal;
方案2:使用useComputed钩子提前计算值
如果需要复用计算结果,可以用useComputed创建计算Observable,再在组件中访问其值:
import {Computed, Show, useObservable, useComputed} from '@legendapp/state/react' import { useInterval } from '../utils/hooks' function LegendStateModal() { const showChild = useObservable(false) const displayText = useComputed(() => showChild.get() ? 'true' : 'false') const textClass = useComputed(() => showChild.get() ? 'text-red-900' : 'text-green-900') useInterval(() => { showChild.set((v) => !v) }, 1000) return ( <div className='flex flex-col'> <span>Showing child: </span> <span className={textClass.get()}>{displayText.get()}</span> <Show if={showChild}> <div>Child element</div> </Show> </div> ) } export default LegendStateModal;
内容的提问来源于stack exchange,提问作者Golam Mostafa
相关产品推荐
相关产品推荐

