首页 > 解决方案 > 如何防止组件被不必要地重新渲染

问题描述

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

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可以看到更新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/>这里的那个组件:

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 Markdown;

标签: reactjs

解决方案


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

解决方案

您可以使用备忘录高阶组件来装饰Markdown组件并提供自定义的areEqual道具比较功能。

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

推荐阅读