Reactjs 防止不必要地重新呈现子元素

Reactjs 防止不必要地重新呈现子元素,reactjs,dom,rendering,react-hooks,Reactjs,Dom,Rendering,React Hooks,我正在react中创建一个全局通知组件,该组件使用上下文为其子级提供createNotification句柄。通知与道具.children一起呈现。如果道具.儿童未更改,是否仍有防止其重新呈现的方法 我尝试过使用React.memo和useMemo(props.children,[props.children])以避免失败 const App = () => { return ( <Notifications> <OtherComponent/&g

我正在react中创建一个全局通知组件,该组件使用
上下文
为其子级提供
createNotification
句柄。通知与
道具.children
一起呈现。如果道具.儿童未更改,是否仍有防止其重新呈现的方法

我尝试过使用
React.memo
useMemo(props.children,[props.children])
以避免失败

const App = () => {
  return (
    <Notifications>
      <OtherComponent/>
    </Notifications/>
  );
}

const Notifications = (props) => {
  const [notifications, setNotifications] = useState([]);
  const createNotification = (newNotification) => {
    setNotifications([...notifications, ...newNotification]);
  }

  const NotificationElems = notifications.map((notification) => <Notification {...notification}/>);
  return (
    <NotificationContext.Provider value={createNotification}>
      <React.Fragment>
        {NotificationElems}
        {props.children}
      </React.Fragment>
    </NotificationContext.Provider>
  );
};

const OtherComponent = () => {
  console.log('Re-rendered');
  return <button onClick={() => useContext(NotificationContext)(notification)}>foo</button>
}
并与
OtherComponent
共享
createNotification
句柄?

您需要使用钩子来创建
createNotification
命令式句柄。否则,您将在
通知
组件的每次呈现上创建一个新函数,这将导致所有使用您的上下文的组件重新呈现,因为无论何时添加通知,您都会传递一个新的处理程序

另外,您可能无意将
newNotification
传播到通知数组中

接下来需要做的是在
setNotifications
中提供setState的名称。它会传递当前的通知列表,您可以使用该列表追加新的通知。这使回调独立于通知状态的当前值。基于当前状态更新状态而不使用更新程序函数通常是错误的,因为react会批量执行多个更新

const Notifications = props => {
    const [notifications, setNotifications] = useState([]);

    // use the useCallback hook to create a memorized handler
    const createNotification = useCallback(
        newNotification =>
            setNotifications(
                // use the callback version of setState
                notifications => [...notifications, newNotification],
            ),
        [],
    );

    const NotificationElems = notifications.map((notification, index) => <Notification key={index} {...notification} />);

    return (
        <NotificationContext.Provider value={createNotification}>
            <React.Fragment>
                {NotificationElems}
                {props.children}
            </React.Fragment>
        </NotificationContext.Provider>
    );
};
完整的工作示例:


工作正常!非常感谢。不过我只有一个问题。由于
通知
已经在函数的范围内,使用
设置状态
的回调版本不是不必要的吗?@RhinoBomb否。原因有两个:第一个也是最重要的react可能会批量调用
设置状态
。这意味着如果没有回调,多个快速更新可能会丢失,因为保存状态的外部变量已经过时。有关详细信息,请参阅。另一个原因是您需要回调独立于外部状态,或者如果添加通知,您将重新创建处理程序。这将导致使用上下文的组件重新渲染。这就是你想要阻止的。
const Notifications = props => {
    const [notifications, setNotifications] = useState([]);

    // use the useCallback hook to create a memorized handler
    const createNotification = useCallback(
        newNotification =>
            setNotifications(
                // use the callback version of setState
                notifications => [...notifications, newNotification],
            ),
        [],
    );

    const NotificationElems = notifications.map((notification, index) => <Notification key={index} {...notification} />);

    return (
        <NotificationContext.Provider value={createNotification}>
            <React.Fragment>
                {NotificationElems}
                {props.children}
            </React.Fragment>
        </NotificationContext.Provider>
    );
};
const OtherComponent = () => {
    // unconditiopnally subscribe to context
    const createNotification = useContext(NotificationContext);

    console.log('Re-rendered');

    return <button onClick={() => createNotification({text: 'foo'})}>foo</button>;
};