如题,想要动态编辑列表,用 dnd-kit 作了拖拽,拖拽功能都正常
触发编辑的按钮放在了兄弟组件里,打算用 useContext 共享一些数据
现在的问题是 useContext 能够成功触发改变数据,但是并不会引起组件重绘,导致无法正常控制组件的修改
好奇这是为什么?有什么解决方法?或者是不是有什么更好的做法?
我看还有的博客里直接把 setState 放到了 useContext 里,结果我用的时候直接报 setxxx not a function ,这是不是取巧失败了?参考的是这篇博客 复杂情况下的组件通信 Hooks:useContext
求大佬赐教 CodeSandbox 示例代码
1
alexsunxl 2022-06-14 14:12:57 +08:00
简单点,用个 recoil 之类的状态管理库?
|
2
TWorldIsNButThis 2022-06-14 14:19:32 +08:00 via iPhone 1
react 触发 rerender 只有一个来源就是 setstate
你直接赋值肯定触发不了啊 把 set 也传过去,onclick 的地方用 set 更新值 另外这里有三个都要传可以考虑用 reducer |
3
steins2628 OP @alexsunxl 项目本体是用 antd pro 搭的,状态管理倒是有
但我这点数据也就组件内部消化,感觉还是 useContext 更适合,就是没用好 |
4
hanai 2022-06-14 14:33:28 +08:00 via iPhone
用法不对,对 context 里的值要用 setState 修改,建议看 react 关于 context 的官方文档。
|
5
westoy 2022-06-14 14:44:40 +08:00
MyDragList 里用 useState 生成 items 和 setItems , 再分别传给 MyDrag 和 MyControl 啊, 不要搞的那么复杂......
|
6
darkengine 2022-06-14 14:54:07 +08:00
看了 codeSandbox 里的效果,其实不需要用到 useContext 的,因为数据只在两级组件里流转
|
7
alexsunxl 2022-06-14 15:10:05 +08:00
@darkengine 你想说传 props 吗 哈哈哈,一直都不喜欢传 props 。稍微改动调整一下结构就有点难受。
|
8
darkengine 2022-06-14 15:12:04 +08:00
@alexsunxl 嗯,就是 props 。我项目里用到 useContext 的场景只有两个,一个是反映当前用户的 account context ,一个是切换 UI 主题的 theme context 。
|
9
FaiChou 2022-06-14 15:58:51 +08:00
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> ); } |
10
FaiChou 2022-06-14 16:05:02 +08:00
|
11
gogogo1203 2022-06-14 16:42:16 +08:00
可以快进到 10:30 左右 你需要的是 selector hook. 市面上有现成的 useSelector
|
12
gogogo1203 2022-06-14 16:43:19 +08:00
很多时候 React 的所谓 re-render, 并不是 Dom 的 re-render. 很多情况下是没有什么大不了的。
|
13
joesonw 2022-06-14 16:55:41 +08:00 via iPhone
要像 useContext 一样用的爽,可以试试 recoil 。
|
14
gogogo1203 2022-06-14 16:58:17 +08:00
我最近做了一个 draggable 的云顶攻略,https://homebh.tk/editor zustand+immer+reducer
const [ tag, clearStore, ] = useEditorStore( (state) => [ state.tag, state.clearStore, ], shallow ) shallow 可以进行对比, 从而避免一些 re-render. useSelector 基本都是这个原理,做一个浅比对 |
15
Exuanbo 2022-06-14 18:07:25 +08:00
Context 只相当于一个依赖注入 API 而不是状态管理工具,你需要把 setState 传进去
|
16
KAROTT 2022-06-14 23:28:16 +08:00
Context 本质还是一个组件,只不过可以跨组件传递和接收属性;要更新数据统一使用 useState 执行后的 set 方法
|
17
demonzoo 2022-06-14 23:34:13 +08:00
你不 setState 怎么触发 re-render 呢。。。
|
18
steins2628 OP @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 大佬做的真好 |