Skip to content

建议:使用 useImperativeHandle hook 代替 ref callback #109

@yzhiJun

Description

@yzhiJun

背景

为了能在普通 JavaScript 函数中调用 <Notification ref={ref} /> 组件实例的方法,目前是通过 class componentref callback 机制实现的,但因为依赖异步回调,导致上层 API 的使用也深受回调影响,如果可以通过某种方式同步获得组件的控制权,那么在 API 使用和封装上会变得优雅很多:

const instance = Notification.newInstance();
const key = instance.add({title: 'xxx'}); // 可以同步返回 key
instance.remove(key);

我们可以通过 useImperativeHandle hook 结合 ref 转发来实现此需求。

大致思路:

  • 使用 Function Component 改写 Notification 组件
  • Notification 组件通过 useImperativeHandle hook 和 forwardRef 暴露内部 add 和 remove 方法
  • Notification.newInstance 通过 createRef 并把 ref.current 同步返回,这样就可以实现同步调用了
const Notification = React.forwardRef((props, ref) => {
  const [notices, setNotices] = useState([]);

  const add = notice => {
    // add notice
  };

  const remove = key => {
    // remove notice
  };

  // expose add & remove methods
  useImperativeHandle(ref, () => ({
    add,
    remove,
  }));

  return (
    <div>{noticeNodes}</div>
  );
});
Notification.newInstance = function newNotificationInstance(properties) {
  const ref = React.createRef();
  // append container stuff....
  ReactDOM.render(<ToastHub {...props} ref={ref} />, div);

  return {
    notice: noticeProps => ref.current.add(noticeProps),
    removeNotice: key => ref.current.remove(key),
    component: ref.current,
    destroy() {
      ReactDOM.unmountComponentAtNode(div);
      div.parentNode.removeChild(div);
    },
  };
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions