这是 React useImperativeHandle 挂钩的正确用例吗?

Is this a correct use case for the React useImperativeHandle hook?

我正在学习 React 挂钩(我对 React 还很陌生),并且正在考虑 useImperativeHandle 的用例。我想到了一个非常有用的场景。

我知道这可以在没有 useImperativeHandle 的情况下完成,但我认为这里有一些优点。

我不知道的...

  1. 我 'discovered the obvious' 这不是真的有用吗? ... 或
  2. 这是错误的形式还是反模式?

我的代码可以正常工作 - 但我正在寻找有关最佳实践的意见。此外,由于目前缺乏关于 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>
  );
};

我完成的是:

  1. 允许父组件 'Foo' 为其子组件提供状态存储 - 因此 Foo 可以 mount/dismount 子组件同时允许它们恢复状态。
  2. 'Bar' 使用 useImperativeHandle 提供一个 'call-in' 因此 Bar 可以否决被卸载,以防它正在做一些重要的事情。

正如我所说,这非常有效。在 React 中,数据和 props 沿着树向下流动,而回调向上流动。这为您提供了一种在特定情况下向下调用树的方法。是否可取?

这是一个反模式:Inject props into the children 没有显式传递 props。

惯用选项是:

因此,如果没有更简单的方法适合我的业务逻辑,我将执行类似以下操作以避免 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})
}