我正在学习 React 钩子(我对 React 相当陌生),并且正在考虑 useImperativeHandle 的用例。我想出了一个非常有用的方案。
我知道这可以在不使用ImperativeHandle的情况下完成,但我认为这里有一些优点。
我不知道的...
- 我是否"发现了显而易见的",但这并没有真正有用?或
- 这是不好的形式,还是反模式?
我的代码正在工作 - 但我正在寻找有关最佳实践的输入。此外,由于现在缺乏有关 useImperativeHandle 的信息,因此这个超越输入引用的示例可能对其他人有用。
如果你想玩它,我在 Github 上发布了一个最小的例子: https://github.com/ericsolberg/react-uih-hook
使用类似于以下内容的标记:
const App = props => {
return (
<Foo>
<Bar>This is Bar 0</Bar>
<Bar>This is Bar 1</Bar>
<Bar>This is Bar 2</Bar>
</Foo>
);
};
我所取得的成就是:
- 允许父组件"Foo"为其子组件提供状态存储 - 因此Foo可以挂载/卸载子组件,同时允许它们恢复状态。
- "Bar"使用useImperativeHandle来提供"呼入",以便Bar可以否决被卸载,以防它正在做重要的事情。
正如我所指出的,这非常有效。在 React 中,数据和 prop 沿着树向动,而回调则向上流动。这为你提供了一种在特定情况下调用树的方法。是否可取?
这是一个反模式:Inject props into the children
没有显式传递道具。
惯用选项是:
- 显式传递道具
- 使用上下文
- 提升状态才能做到以上2项
- 渲染道具
因此,如果没有更简单的东西适合我的业务逻辑,我会做如下操作以避免 Foo 和 Bar 之间无形的紧密耦合:
const App = () => (
<Foo>
{({selector, saveStateFactory}) => (<>
<Bar state={selector(0)} saveState={saveStateFactory(0)} />
<Bar state={selector(1)} saveState={saveStateFactory(1)} />
</>)}
</Foo>
)
const Foo = () => {
const [state, dispatch] = useReducer(...)
const selector = (id) => state[id]
const saveStateFactory = (id) => {
return (payload) => dispatch({type: id, payload})
}
// do something with whole state that cannot be done in App nor Bar
return children({selector, saveStateFactory})
}