【问题标题】:Rendering multiple input fields causing lag after 200 items渲染多个输入字段导致 200 个项目后滞后
【发布时间】:2020-07-19 20:49:17
【问题描述】:

我有一个项目,我可以有 n 个输入字段。当我添加 200 个项目之后,它开始滞后。演示:https://testcreate.vivekneel.now.sh/create (测试:关注最后一个输入并尝试按回车键创建新输入)

源代码。 :https://github.com/VivekNeel/Create-Test

这是我的主要容器:

import React, { useState } from "react";

import CreateTerms from "./CreateTerms";
import { initTerms, contructTermObject } from "./utils";
import { Container } from "@material-ui/core/";

const CreateStudySetContainer = () => {
  const [terms, setTerms] = useState(initTerms);

  const [inputIdToFocus, setInputIdToFocus] = useState(null);

  const handleCreateTerm = () => {
    const newTerm = contructTermObject(terms.length + 1, 2);
    const newTerms = [...terms, newTerm];
    setInputIdToFocus(terms.length + 1);
    setTerms(newTerms);
  };
  console.log("....rendering");
  return (
    <Container maxWidth={"md"}>
      <CreateTerms
        terms={terms}
        inputIdToFocus={inputIdToFocus}
        createTerm={handleCreateTerm}
      />
      ;
    </Container>
  );
};

export default CreateStudySetContainer;

这是 CreateTerms 代码:

import React from "react";
import CreateFacts from "./CreateFacts";

import { withStyles, Card } from "@material-ui/core/";
import ContentItemRow from "./ContentItemRow";
const styles = () => ({
  card: {
    marginBottom: 16,
  },
});
const CreateTerms = (props) => {
  const { terms, classes, createTerm, inputIdToFocus } = props;
  return (
    <div className={classes.container}>
      {terms.map(({ node: { term } }, index) => {
        return (
          <Card key={term.id} className={classes.card}>
            <p>{index}</p>
            <ContentItemRow
              autoFocus={term.id === inputIdToFocus}
              createTerm={createTerm}
              term={term}
            />
            ;
          </Card>
        );
      })}
    </div>
  );
};

export default withStyles(styles)(CreateTerms);

这是 ContentItemRow :

import React from "react";
import CreateFacts from "./CreateFacts";

import { withStyles } from "@material-ui/core/";
import ContentEditor from "./ContentEditor";
const styles = {
  container: {
    display: "flex",
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "flex-start",
  },
  term: {
    marginRight: 16,
    flex: 1,
  },
  facts: {
    flex: 1,
  },
};

const ContentItemRow = (props) => {
  const { term, classes, createTerm, autoFocus } = props;
  return (
    <div className={classes.container}>
      <div className={classes.term}>
        <ContentEditor
          autoFocus={autoFocus}
          createTerm={createTerm}
          placeholder={"New term"}
        />
      </div>
      <div className={classes.facts}>
        {term.facts.map(({ fact }) => {
          return (
            <ContentEditor
              key={fact.id}
              createTerm={createTerm}
              placeholder={"New fact"}
            />
          );
        })}
      </div>
    </div>
  );
};

export default withStyles(styles)(ContentItemRow);

这是内容编辑器:

import React from "react";

import { TextField } from "@material-ui/core/";

const ContentEditor = (props) => {
  const { placeholder, createTerm, autoFocus } = props;

  const handleOnKeyDown = (event) => {
    const { keyCode } = event;
    if (keyCode === 13) {
      createTerm();
    }
  };
  return (
    <TextField
      onKeyDown={handleOnKeyDown}
      fullWidth
      autoFocus={autoFocus}
      placeholder={placeholder}
    />
  );
};

export default ContentEditor;

调试时,我注意到 dom 只更新添加的最后一个 div。我不知道滞后是从哪里来的。

【问题讨论】:

  • 200 项目相比,它与199 项目相比是否滞后更多?
  • 第199条也是一样!
  • 在您的情况下,“200 个项目”并不意味着渲染大约 200 个组件,甚至不接近。根据您的代码,对于每个项目,您渲染 1 个“术语”输入和 i“事实”输入,所以如果我没记错的话,您实际上至少渲染了 200 + 20100 = 20200成分 (!!!)。我想这对于 React 来说是相当多的(它需要大约 500MB 的内存)。

标签: javascript reactjs material-ui textfield next.js


【解决方案1】:

不确定这是否可行,但您可以尝试以下方法:

const ContentItemRow = React.memo(function ContentItemRow (props) => {

并防止重新创建创建术语处理程序:

const handleCreateTerm = useCallback(() => {
  setTerms((terms) => {
    const newTerm = contructTermObject(
      terms.length + 1,
      2
    );
    const newTerms = [...terms, newTerm];
    setInputIdToFocus(terms.length + 1);
    return newTerms;
  });
}, []);

【讨论】:

  • 并不是所有的东西都在 dom 中渲染。它只是最后一个 div 正在更新它的 dom。所以 react 已经跳过了渲染。我仍然想知道为什么当它只是在 dom 中更新最后一个 div 时这仍然很慢。
  • 我想在不使用 React.memo 的情况下进行优化,因为即使是 memo 也会花时间对所有项目进行浅层检查!
  • It's not the every things is rendering in the dom. 我不这么认为,你有没有在反应开发工具中尝试分析器?您正在为每个渲染创建一个处理程序,这将导致虚拟 dom 比较失败并导致每个项目重新渲染。
  • 我尝试了您的解决方案,似乎有效。但由于没有用于 useCallback 的 deps,我只能添加另一个输入,但不超过这个。
猜你喜欢
  • 2021-02-03
  • 1970-01-01
  • 2021-06-04
  • 2015-12-03
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 2019-09-20
  • 1970-01-01
相关资源
最近更新 更多