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

问题描述 投票:2回答:1

我正在反应中创建一个全局通知组件,使用createNotification为其子项提供Context句柄。通知与props.children一起呈现。反正是否有阻止重新渲染props.children,如果他们没有改变?

我尝试使用React.memouseMemo(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>
}

每次创建新的notification时,props.children都会被重新渲染,即使其中没​​有任何实际变化。它只是添加了元素。如果你有一个很大的应用程序,并且每个notification都会重新呈现,那么这可能会非常昂贵。如果无法阻止这种情况,我该如何拆分它以便我可以这样做:

<div>
  <OtherComponent/>
  <Notifications/>
</div>

并与OtherComponent分享createNotification手柄?

reactjs dom rendering react-hooks
1个回答
3
投票

你需要使用useCallback钩子来创建你的createNotification命令式处理程序。否则,您将在Notifications组件的每个渲染上创建一个新函数,这将导致所有消耗上下文的组件重新渲染,因为每次添加通知时总是会传递一个新的处理程序。

你也可能并不想将newNotification传播到通知数组中。

接下来你需要做的是在updater callback version中提供setState的setNotifications。它会传递当前的通知列表,您可以使用它添加新的通知。这使您的回调独立于通知状态的当前值。在不使用更新程序功能的情况下基于当前状态更新状态通常是错误的,因为反应批处理多个更新。

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>
    );
};

另一个问题是你有条件地调用不允许的useContext钩子。 Hooks must be called unconditionally

const OtherComponent = () => {
    // unconditiopnally subscribe to context
    const createNotification = useContext(NotificationContext);

    console.log('Re-rendered');

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

完全工作的例子:

Edit 31wx7q9y75

© www.soinside.com 2019 - 2024. All rights reserved.