如何防止组件不必要地重新渲染

时间:2021-06-07 19:39:54

标签: reactjs

我将从代码开始。我有一个类似于这个的无状态功能组件

export const Edit Topic = (_title, _text) {
    const [title, setTitle] = useState(_title)
    const [text, setText] = useState(_text)

    return (
      <>
         <InputText props={{ fieldName:"Title:", value:title, setValue:setTitle, placeHolder:"Topic Title"}}/>
         <InputTextArea props={{ fieldName:"Markdown Text:", text, setText }}/>
         <PreviewBox text={text}/>
      </>
   )
}

我有 PreviewBox,当它打开时,页面呈现需要更长的时间,因为 text 可能很长。每次我更改 PreviewBox 中的文本时,InputTextArea 都需要重新渲染,这很好。

我遇到的问题是,当我更改 title 的值时,它也会更新 <PreviewBox/>,这是不希望的。

如何确保 <PreviewBox/> 仅在 text 更改时更新,而在 title 更改时不更新?

我相信重新渲染正在发生的原因是因为如果我关闭 PreviewBox,更新 title 时没有延迟,但是当 PreviewBox 可见时,更新 { {1}} 滞后。


title

由于上面还包含 import style from "../styles/CreateTopic.module.css" import { Component } from "react" import Markdown from "./Markdown"; export class PreviewBox extends Component { constructor(props) { super(props) this.state = { isShow: true } } toggleShow = () => { console.log("begin isShow", this.state) this.setState(state => ({ isShow: !state.isShow})) } render() { return ( <> <div className={style.wrptoggle}> <button className={style.btn} onClick={this.toggleShow}>Preview</button> </div> {this.state.isShow ? <div className={style.wrppreviewbox}> <div className={style.previewbox}> <Markdown text={this.props.text}/> </div> </div> : null} </> ) } } ,这里是那个组件:

<Markdown/>

1 个答案:

答案 0 :(得分:1)

我没有看到 PreviewBox 中的任何复杂性会导致任何渲染延迟,因此我可能认为它是 Markdown 组件在重新渲染时可能需要一些时间“工作”,因为您说“切换关闭 PreviewBox,更新 title 时没有延迟。

解决方案

您可以使用 memo 高阶组件来装饰 Markdown 组件并提供自定义的 areEqual props 比较函数。

import { memo } from 'react';
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import ReactMarkdown from "react-markdown";
import "katex/dist/katex.min.css";

const Markdown = ({ text }) => {
  return (
    <div>
      <ReactMarkdown
        remarkPlugins={[remarkMath]}
        rehypePlugins={[rehypeKatex]}
        children={text}
      />
    </div>
  );
};
 
export default memo(Markdown);
<块引用>

默认情况下,它只会浅比较 props 中的复杂对象 目的。如果您想控制比较,您还可以提供 自定义比较函数作为第二个参数。

const areEqual = (prevProps, nextProps) => {
  return prevProps.text === nextProps.text;
};
 
export default memo(Markdown, areEqual);