React useContext 值改变不引发重绘 - V2EX
steins2628
V2EX    React

React useContext 值改变不引发重绘

  •  
  •   steins2628 Jun 14, 2022 4780 views
    This topic created in 1429 days ago, the information mentioned may be changed or developed.

    如题,想要动态编辑列表,用 dnd-kit 作了拖拽,拖拽功能都正常

    触发编辑的按钮放在了兄弟组件里,打算用 useContext 共享一些数据

    现在的问题是 useContext 能够成功触发改变数据,但是并不会引起组件重绘,导致无法正常控制组件的修改

    好奇这是为什么?有什么解决方法?或者是不是有什么更好的做法?

    我看还有的博客里直接把 setState 放到了 useContext 里,结果我用的时候直接报 setxxx not a function ,这是不是取巧失败了?参考的是这篇博客 复杂情况下的组件通信 Hooks:useContext

    求大佬赐教 CodeSandbox 示例代码

    Supplement 1    Jun 17, 2022
    终于解决了,半路还被 useState 异步同步坑了,不过现在是能用了
    useReducer 和 useState 方法都实现了一遍,代码还是在 codeSandbox 里
    希望对有需要的人有点参考价值
    18 replies    2022-06-16 10:10:41 +08:00
    alexsunxl
        1
    alexsunxl  
       Jun 14, 2022
    简单点,用个 recoil 之类的状态管理库?
    TWorldIsNButThis
        2
    TWorldIsNButThis  
       Jun 14, 2022 via iPhone   1
    react 触发 rerender 只有一个来源就是 setstate
    你直接赋值肯定触发不了啊
    把 set 也传过去,onclick 的地方用 set 更新值
    另外这里有三个都要传可以考虑用 reducer
    steins2628
        3
    steins2628  
    OP
       Jun 14, 2022
    @alexsunxl 项目本体是用 antd pro 搭的,状态管理倒是有
    但我这点数据也就组件内部消化,感觉还是 useContext 更适合,就是没用好
    hanai
        4
    hanai  
       Jun 14, 2022 via iPhone
    用法不对,对 context 里的值要用 setState 修改,建议看 react 关于 context 的官方文档。
    westoy
        5
    westoy  
       Jun 14, 2022
    MyDragList 里用 useState 生成 items 和 setItems , 再分别传给 MyDrag 和 MyControl 啊, 不要搞的那么复杂......
    darkengine
        6
    darkengine  
       Jun 14, 2022
    看了 codeSandbox 里的效果,其实不需要用到 useContext 的,因为数据只在两级组件里流转
    alexsunxl
        7
    alexsunxl  
       Jun 14, 2022
    @darkengine 你想说传 props 吗 哈哈哈,一直都不喜欢传 props 。稍微改动调整一下结构就有点难受。
    darkengine
        8
    darkengine  
       Jun 14, 2022
    @alexsunxl 嗯,就是 props 。我项目里用到 useContext 的场景只有两个,一个是反映当前用户的 account context ,一个是切换 UI 主题的 theme context 。
    ethusdt
        9
    ethusdt  
       Jun 14, 2022
    ContextAPI 在历史上的确有过深层次子组建不能刷新的问题, 但已经解决了. 也就是说 Context 解决了深层子组件 re-render 链被打断的这个问题, 写了一个简单的 demo 来验证下:

    要注意下 Component1 是被 React.memo(), 其次 Provider 的 value 也需要用 useMemo() 来固定, 否则每次点击 update 都会变成新的 setVal 值.

    const COntext= createContext()
    const Component1 = React.memo(function() {
    console.log('componet1')
    return (
    <div>
    <h1>Component1</h1>
    <Component2 />
    </div>
    )
    })
    function Component2() {
    console.log('componet2')
    const { val } = useContext(Context);
    return (
    <div>
    <h1>Component2</h1>
    <h2>{val}</h2>
    </div>
    )
    }
    function App() {
    const [, forceUpdate] = useReducer(x=>x+1,0);
    const [val, setVal] = useState(null);
    return (
    <Context.Provider value={useMemo(()=>({ val, setVal }), [val])}>
    <Component1 />
    <button OnClick={forceUpdate}>update</button>
    <button OnClick={() => setVal(Date.now().toString())}>setRandom</button>
    </Context.Provider>
    );
    }
    ethusdt
        10
    ethusdt  
       Jun 14, 2022
    gogogo1203
        11
    gogogo1203  
       Jun 14, 2022
    可以快进到 10:30 左右 你需要的是 selector hook. 市面上有现成的 useSelector
    gogogo1203
        12
    gogogo1203  
       Jun 14, 2022
    很多时候 React 的所谓 re-render, 并不是 Dom 的 re-render. 很多情况下是没有什么大不了的。
    joesonw
        13
    joesonw  
       Jun 14, 2022 via iPhone
    要像 useContext 一样用的爽,可以试试 recoil 。
    gogogo1203
        14
    gogogo1203  
       Jun 14, 2022
    我最近做了一个 draggable 的云顶攻略,https://homebh.tk/editor zustand+immer+reducer

    const [
    tag,
    clearStore,
    ] = useEditorStore(
    (state) => [
    state.tag,
    state.clearStore,
    ],
    shallow
    )

    shallow 可以进行对比, 从而避免一些 re-render. useSelector 基本都是这个原理,做一个浅比对
    Exuanbo
        15
    Exuanbo  
       Jun 14, 2022
    Context 只相当于一个依赖注入 API 而不是状态管理工具,你需要把 setState 传进去
    KAROTT
        16
    KAROTT  
       Jun 14, 2022
    Context 本质还是一个组件,只不过可以跨组件传递和接收属性;要更新数据统一使用 useState 执行后的 set 方法
    demonzoo
        17
    demonzoo  
       Jun 14, 2022
    你不 setState 怎么触发 re-render 呢。。。
    steins2628
        18
    steins2628  
    OP
       Jun 16, 2022
    @TWorldIsNButThis
    试着改了 useReducer 的版本,但在拖拽更改列表顺序的时候,state.listItems 无法 map, 打印出来是数组应该是可以 map 的,这是 state 下 的特殊情况,还是其实我用的方法不对?

    @hanai
    @Exuanbo
    @KAROTT
    @demonzoo
    试着改了 useState 的版本,但在父组件的 useEffect 里赋初值好像也不会触发子组件重绘
    看着像是 setState 失败了,是不是我传 set 的方法有问题?
    https://codesandbox.io/s/dnd-kit-with-custom-item-8oc96b?file=/src/useContext_useState/index.tsx


    @westoy
    @darkengine
    直接 props 是成功的,但还是想试试 useContext ,感觉会简洁很多,以后也好改


    @FaiChou 学习了


    @gogogo1203 原来还有这种 hook 学习了


    @joesonw 暂时想用原生的试试,因为这个不需要全局状态


    @gogogo1203 大佬做的真好
    About     Help     Advertise     Blog     API     FAQ     Solana     4657 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 68ms UTC 05:34 PVG 13:34 LAX 22:34 JFK 01:34
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86