将对象值添加到 React 的 useMemo 挂钩

Adding object values to useMemo hook for React

我正在尝试使用从数据库中提取的数据创建一个 react-table 组件。从我阅读的文档 (https://react-table.tanstack.com/docs/quick-start) 来看,react-table 库似乎使用 useMemo 挂钩来创建将显示在 table 上的数据。但是,我在实际向 useMemo 挂钩添加数据时遇到了麻烦,因为我不熟悉它。

我有一个简单的 JS 对象,它保存我们数据库中发生的每一类中断的实例计数。获得计数后,我尝试将其传递给我的 useMemo 实例,但返回未定义 'streamCount' 的属性。我想我错误地将对象传递给了 useMemo。感谢任何帮助。

function Leaderboard(props){
    const data = props.tableData;
    console.log(data); //this is the data that is pulled from our DB and is passed as a prop into the component
    
    let counts = {
      streamCount: 0,
      powerCount: 0,
      internetCount: 0,
      gamingPlatformCount: 0,
      cableCount: 0,
      websiteCount: 0,
    } //the object that holds the number of instances each category occurs in our data

    for(var i = 0; i < data.length; i++){ //checks the data and updates the counts for each category
      switch(data[i].service_type) {
        case "Streaming":
          counts.streamCount += 1;
          break;
        case "Power":
          counts.powerCount+= 1;
          break;
        case "Internet":
          counts.internetCount+= 1;
          break;
        case "Gaming Platform":
          counts.gamingPlatformCount += 1;
          break;
        case "Cable":
          counts.cableCount += 1;
          break;
        case "Website":
          counts.websiteCount += 1;
          break;
        default:
          break;
      }
    }

    console.log(counts) //This returns the correct values of each count when line 41-69 is commented, but returns 0 for all values when those lines are uncommented.

    let outageCounts = React.useMemo(
      (counts) => [
        {
          type: 'Streaming',
          count: counts.streamCount,
        },
        {
          type: 'Power',
          count: counts.powerCount,
        },
        {
          type: 'Internet',
          count: counts.internetCount,
        },
        {
          type: 'GamingPlatform',
          count: counts.gamingPlatformCount,
        },
        {
          type: 'Cable',
          count: counts.cableCount,
        },
        {
          type: 'Website',
          count: counts.websiteCount,
        },
      ],
      []
    );
    
    //this will be updated to have the accessor be 'count' from outageCounts instead of 'service_type' from data when the bug is resolved. For now it is just using data to test to see if the table would render at all.
    const columns = React.useMemo(
        () => [
          {
            Header: 'Service Type',
            accessor: 'service_type',
          },
        ],
        []
    );
    
    const {
        getTableProps,
        getTableBodyProps,
        headerGroups,
        rows,
        prepareRow,
    } = useTable({ columns, data}) //data will eventually be changed to outageCounts
    
    return (
        <table {...getTableProps()} style={{ border: 'solid 1px blue' }}>
          <thead>
            {headerGroups.map(headerGroup => (
              <tr {...headerGroup.getHeaderGroupProps()}>
                {headerGroup.headers.map(column => (
                  <th
                    {...column.getHeaderProps()}
                    style={{
                      borderBottom: 'solid 3px red',
                      background: 'aliceblue',
                      color: 'black',
                      fontWeight: 'bold',
                    }}
                  >
                    {column.render('Header')}
                  </th>
                ))}
              </tr>
            ))}
          </thead>
          <tbody {...getTableBodyProps()}>
            {rows.map(row => {
              prepareRow(row)
              return (
                <tr {...row.getRowProps()}>
                  {row.cells.map(cell => {
                    return (
                      <td
                        {...cell.getCellProps()}
                        style={{
                          padding: '10px',
                          border: 'solid 1px gray',
                          background: 'papayawhip',
                        }}
                      >
                        {cell.render('Cell')}
                      </td>
                    )
                  })}
                </tr>
              )
            })}
          </tbody>
        </table>
    );
  }
export default Leaderboard;

useMemo 钩子的回调函数不接受任何参数,它只接受一个回调函数,returns 一个你想要或需要记忆的值,以及一个依赖数组。

useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Returns a memoized value.

Pass a “create” function and an array of dependencies. useMemo will only recompute the memoized value when one of the dependencies has changed. This optimization helps to avoid expensive calculations on every render.

将计算计数的逻辑移动到 useMemo 回调中,并使用 data(道具值)作为依赖项。您可以 simplify/reduce 通过抽象将 service_type 映射到 counts 键之一然后映射回来但仅使用 service_type 作为 counts键。通过此更改,您可以简单地使用动态对象属性来更新每种中断类型的计数。计算完计数后,从对象创建一个键值对数组,并将其映射到具有 typecount 键的对象数组。

const outageCounts = React.useMemo(() => {
  const counts = {
    Streaming: 0,
    Power: 0,
    Internet: 0,
    "Gaming Platform": 0,
    Cable: 0,
    Website: 0
  };

  data.forEach(({ service_type }) => {
    if (Object.hasOwnProperty.call(counts, service_type)) {
      counts[service_type] += 1;
    }
  });

  return Object.entries(counts).map(([type, count]) => ({ type, count }));
}, [data]);

function App({ data = [] }) {
  const outageCounts = React.useMemo(() => {
    const counts = {
      Streaming: 0,
      Power: 0,
      Internet: 0,
      "Gaming Platform": 0,
      Cable: 0,
      Website: 0
    };

    data.forEach(({ service_type }) => {
      if (Object.hasOwnProperty.call(counts, service_type)) {
        counts[service_type] += 1;
      }
    });

    return Object.entries(counts).map(([type, count]) => ({ type, count }));
  }, [data]);

  //console.log({ outageCounts });

  return (
    <div className="App">
      <h1>Outage Counts</h1>
      <ul>
        {outageCounts.map(({ type, count}) => (
          <li key={type}>
            {type}: {count}
          </li>
        ))}
      </ul>
    </div>
  );
}

const service_types = [
  "Streaming",
  "Power",
  "Internet",
  "Gaming Platform",
  "Cable",
  "Website"
];

// Generate "random" outage data
const data = Array.from({ length: Math.floor(Math.random() * 1000) }, () => ({
  service_type: service_types[Math.floor(Math.random() * service_types.length)]
}));

const rootElement = document.getElementById("root");
ReactDOM.render(
  <App data={data} />,
  rootElement
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root" />