【问题标题】:Why is the component fully re-rendering when updating a single state through context?为什么通过上下文更新单个状态时组件会完全重新渲染?
【发布时间】:2021-01-14 13:32:04
【问题描述】:

我创建了一个包含两列的页面:

  1. 在一列中显示项目列表
  2. 在另一列中,我应该显示一些与所选项目相关的信息

我目前的代码是:

import { INavLink, INavLinkGroup, INavStyles, Nav } from "@fluentui/react";
import React, { createContext, useContext, useState } from "react";

interface HistoryTtem {
  id: string;
}

interface AppState {
  selectedItem: string | undefined;
  updateSelectedItem: (value: string | undefined) => void;
  items: Array<HistoryTtem>;
}

const AppContext = createContext<AppState>({
  selectedItem: undefined,
  updateSelectedItem: (value: string | undefined) => {},
  items: []
});

const App = () => {
  const Column1 = () => {
    const rootState: AppState = useContext(AppContext);

    const getNavLinks: Array<INavLink> = rootState.items.map((item) => ({
      name: item.id,
      key: item.id,
      url: ""
    }));

    const groups: Array<INavLinkGroup> = [
      {
        links: getNavLinks
      }
    ];

    const navStyles: Partial<INavStyles> = {
      root: {
        boxSizing: "border-box",
        border: `1px solid #eee`,
        overflowY: "auto"
      }
    };

    const onItemClick = (
      e?: React.MouseEvent<HTMLElement>,
      item?: INavLink
    ) => {
      if (item && item.key) {
        rootState.updateSelectedItem(item.key);
      }
    };

    return (
      <Nav
        onLinkClick={onItemClick}
        selectedKey={rootState.selectedItem}
        ariaLabel="List of previously searched transactions"
        styles={navStyles}
        groups={groups}
      />
    );
  };

  const Column2 = () => {
    return <div>aaa</div>;
  };

  const [historyItems, setHistoryItems] = useState<Array<HistoryTtem>>([
    {
      id: "349458457"
    },
    {
      id: "438487484"
    },
    {
      id: "348348845"
    },
    {
      id: "093834845"
    }
  ]);
  const [selectedItem, setSelectedItem] = useState<string>();

  const updateSelectedItem = (value: string | undefined) => {
    setSelectedItem(value);
  };

  const state: AppState = {
    selectedItem: selectedItem,
    updateSelectedItem: updateSelectedItem,
    items: historyItems
  };

  return (
    <AppContext.Provider value={state}>
      <div>
        <Column1 />
        <Column2 />
      </div>
    </AppContext.Provider>
  );
};

export default App;

如您所见,我有一个根状态,它将用于驱动从第一列内部触发的第二列的更新。但它不起作用。当我单击一个项目时,第一列中的整个组件正在重新渲染,而它应该只更改选定的项目。

请在此处找到CodeSandbox

【问题讨论】:

    标签: reactjs typescript react-typescript fluent-ui fluentui-react


    【解决方案1】:

    你不应该嵌套组件函数。

    Column1 的标识会随着 App 的每次渲染而变化,因为它是一个内部函数,这使得 React 认为它需要协调一切。

    Column1Column2 移至模块级别。

    【讨论】:

    • 这很有意义。我实际上每次都犯了一个严重的错误,因为到目前为止,我认为只有一个组件在其中定义使用组件是一种好习惯,但这实际上只是在做坏事……该模式可能仅用于在 HOC 中
    • 从技术上讲,您可以使用React.useCallback() 来暗示 React 内部组件不会改变,但这更加令人困惑。 :)
    【解决方案2】:

    使react rerender 的原因有两点:

    1. 状态变化

    2. 道具变化

    您有一个App Component,它是您的components 的根,它有一个selectedItem 状态,当单击item 时它会发生变化,因此您有一个新状态,新状态将导致重新渲染

    【讨论】:

    • 或者,正如我在回答中所解释的,完全改变了组件:)
    • @AKX 当然 :),那将是 3 号
    猜你喜欢
    • 2020-11-04
    • 2020-08-14
    • 2021-08-21
    • 2019-06-17
    • 2018-06-05
    • 2023-03-09
    • 1970-01-01
    • 2019-12-12
    • 2021-05-19
    相关资源
    最近更新 更多