react-hooks
react-hooks copied to clipboard
feat(control): Introduce control hooks
目标
通过hooks简化弹窗类组件的调用。
现状
实现弹窗交互时我们通常写出这样的代码。当组件需求越来越复杂,或者一个页面中出现多个弹窗时,这样的写法使得组件内 state 满天飞,可维护性急剧下降。同时,打开弹窗操作所引起的 state 更新会导致整个组件刷新,照成性能问题。
function Demo() {
const [editId, setEditId] = useState();
const [editField, setEditField] = useState();
const EditorDialog = fieldToEditorMap[editField];
const openEditor = useCallback((id, field) => {
setEditId(id)
setEditField(field)
}, [setEditId, setEditField]);
return <>
<MassiveTable>
...
<SomeButton onClick={() => openEditor(xxxId, field)} />
...
</MassiveTable>
{EditorDialog && <EditorDialog id={editId} onClose={() => setEditField(undefined)} />}
</>;
}
解决
把弹窗相关逻辑独立成组件提升可维护性。并且通过 useControl
和 useControlSource
hook 来关联两者,实现简单易用。
function Demo() {
const [ControlledEditor, {open: openEditor}] = useControl(Editor);
return <>
<MassiveTable>
<SomeButton onClick={() => openEditor(xxxId, field)} />
</MassiveTable>
<ControlledEditor />
</>;
}
function Editor(props, ref) {
const [[editId, editField], {close}] = useControlSource(ref, (setState) => ({
open: (id, field) => setState([id, field]),
close: () => setState([])
}), []);
const EditorDialog = fieldToEditorMap[editField];
{EditorDialog && <EditorDialog id={editId} onClose={close} />}
}
这样无论是直接使用 open 还是把它通过 context 往下传递,调用它开关弹窗都不会导致其它地方的无意义刷新。
目前在业务代码里用起来还挺方便的,所以感觉可以放到 huse 里面。
更详细的例子可以看 demo 实现。
我终于看懂了……核心是利用ref
跨组件地传递一些命令式的功能,这个思路很棒
具体到类型的完备性和命名,我再仔细推敲一下