🔥🔥🔥 Знаете ли вы все эти способы избежать повторного рендеринга компонентов React?

внешний интерфейс React.js
🔥🔥🔥 Знаете ли вы все эти способы избежать повторного рендеринга компонентов React?

Я использую React уже три года, и за эти три года у меня накопилось много лучших практик по оптимизации кода React, сегодня я напишу некоторые из них и поделюсь с вами. Последующие действия, чтобы узнать, популярна ли статья, а затем решить, стоит ли делиться следующей информацией.

Для каждой передовой практики в этой статье я приведу два примера, один хороший и один плохой для сравнения, и приведу.gifПредварительный просмотр изображения.

Эта статья в основном оптимизирует следующие три ситуации:

  • Обновление родительского компонента приводит к отображению дочернего компонента
  • Неправильное написание реквизита вызывает отрисовку компонента
  • Обновления контекста заставляют компонент отображаться

После прочтения статьи, если вы считаете, что она была вам полезна, пожалуйста, помогите поставить лайк, Ваш лайк - самая большая мотивация для моего творчества.Комментируйте и ставьте лайк, чтобы получить исходный код! !

Обновление родительского компонента приводит к отображению дочернего компонента

Пример класса

❎ Предварительный просмотр примера ошибки

1.classBad.gif

❎ Примеры ошибок

import React, { Component } from "react";
class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  render() {
    const { count } = this.state;
    return (
      <div className="parent">
        <h5>错误示例</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        <Son />
      </div>
    );
  }
}

class Son extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件重新渲染了!!");
    return <div className="son">子组件</div>;
  }
}

export { Parent, Son };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере изменение состояния в родительском компоненте приводит к повторному рендерингу дочернего компонента Код, написанный таким образом, является очень нормальным способом написания, но серьезно, он все равно приведет к потере производительности. Ведь дочерний компонент перерисовывается. ! Далее давайте посмотрим, как решить эту проблему!

Примечание: Этот пример не означает запрет на написание такого кода, на самом деле оптимизация тоже зависит от сцены! !

✅ Правильный пример 1

import React, { Component, PureComponent } from "react";
class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  render() {
    const { count } = this.state;
    return (
      <div className="parent">
        <h5>正确示例1</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        <Son />
      </div>
    );
  }
}

class Son extends PureComponent {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件重新渲染了!!");
    return <div className="son">子组件</div>;
  }
}

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы в основном заимствуемPureComponentУнаследуйте этот класс, React автоматически выполнит его для нас.shouldComponentUpdateНеглубокое обновление оптимизации сравнения для реквизитов.

Примечание: На самом деле, серьезно, в React компонент будет выполняться React.createElement(Son), а ссылка Props полученного компонента каждый раз новая, поэтому это вызовет повторный рендеринг!

✅ Правильный пример 2

import React, { Component } from "react";
class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  render() {
    const { count } = this.state;
    const { children } = this.props;
    return (
      <div className="parent">
        <h5>正确示例2</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        {children}
      </div>
    );
  }
}

export default Parent;

<Parent>
  <Son />
</Parent>

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В оптимизации этого примера мы отделяем компоненты с состоянием от компонентов без состояния, используяchildrenПередайте компоненты без состояния. Это позволит избежать бессмысленного повторного рендеринга! Так почему же это позволяет избежать повторного рендеринга? потому что непосредственно в государственном компоненте используетсяchildrenРендеринг дочерних компонентов напрямую позволяет избежать использования React в компонентах с отслеживанием состояния.React.createElement(Son)Рендеринг дочерних компонентов! ! Это тоже можно оптимизировать!

✅ Правильный пример 3

import React, { Component, memo } from "react";
import { Son } from "./Bad";

const MemoSon = memo(() => <Son></Son>);

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  render() {
    const { count } = this.state;
    return (
      <div className="parent">
        <h5>正确示例3</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        <MemoSon />
      </div>
    );
  }
}

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В данном примере идея реализации оптимизации аналогична упомянутой в Примере 1. Мы позаимствовалиmemoфункция, которая на самом делеФункциональный компонентПодготовленные средства оптимизации. Вот и мы наглые и вынуждены этим пользоваться! ! , идея избежать повторного рендеринга на самом деле является отсылкой к Props. Решайте рендерить или нет! !

✅ Правильный пример 4

import React, { Component, useState, Fragment } from "react";
import { Son } from "./Bad";

const ClickCount = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <Fragment>
      <div>
        <h5>正确示例4</h5>
        <p>父组件Count--{count}</p>
        <button onClick={handleClick}>增加</button>
      </div>
    </Fragment>
  );
};

class Parent extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="parent">
        <ClickCount />
        <Son />
      </div>
    );
  }
}

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере наш метод оптимизации в основном состоит в том, чтобы предложить компонент состояния в компонент, чтобы изменение состояния было отделено от подкомпонента. Также избегайте повторного рендеринга дочерних компонентов! !

Примечание: Если серьезно, то этот метод оптимизации пока используется очень мало, используйте его по ситуации! !

Пример хуков

Предварительный просмотр примера ошибки

1.HooksBad.gif

❎ Примеры ошибок

import { useState } from "react";
const Son = () => {
  console.log("子组件重新渲染了!!");
  return <div className="son">子组件</div>;
};

const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>错误示例</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      <Son />
    </div>
  );
};

export { Son, Parent };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

Вышеупомянутое написание также очень нормально для хуков, но по сравнению с компонентом класса,Функциональный компонентОсобенность в том, что при каждом повторном рендеринге компонента функция будет выполняться заново. Для компонента класса он будет выполнен только один раз.new ClassНа самом деле, даже подумать об этом довольно страшно. Для композиции функций каждое выполнение означает новый контекст, новую переменную и новую область. Поэтому следует уделять больше внимания оптимизации производительности функциональных компонентов.

✅ Правильный пример 1

import { useState } from "react";

const Parent = ({ children }) => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>正确示例1</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      {children}
    </div>
  );
};

export default Parent;

<Parent>
  <Son />
</Parent

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы использовалиchildrenПринцип прямого рендеринга подкомпонентов упоминался в примере с компонентом Class выше, и такая оптимизация также позволяет избежать бессмысленного рендеринга.

Примечание: Серьезно, метод оптимизации в сочетании с характеристиками функциональных компонентов на самом деле является временным решением!

✅ Правильный пример 2

import { useState, useMemo } from "react";
import { Son } from "./Bad";
const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>正确示例2</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      {useMemo(
        () => (
          <Son />
        ),
        []
      )}
    </div>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы использовалиuseMemoВ этом оптимизированном хуке мы кэшируем компонент Son.Только при изменении зависимостей мы будем повторно выполнять функцию для завершения повторного рендеринга.Другие тайминги гарантированы.memoizedодинаково, что помогает избежать дорогостоящих вычислений при каждом рендеринге. Это также позволяет избежать повторного объявления переменных, функций, областей видимости и т. д. каждый раз в дочернем компоненте.

说明:我觉得这个优化手段绝对称得上神来之笔,因为 useMemo 保存了组件的引用,没有重新执行函数组件,因此避免了组件内的变量,函数声明,和作用域的声明。从而优化了性能。 Хороший! !

✅ Правильный пример 3

import { useState, memo } from "react";
import { Son } from "./Bad";

const SonMemo = memo(Son);

const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>正确示例3</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      <SonMemo />
    </div>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы используемmemoЭтот API в основном предназначен для сравнения того, изменилась ли ссылка реквизита, чтобы избежать повторного рендеринга дочерних компонентов!

Неправильное написание реквизита вызывает отрисовку компонента

Пример класса

❎ Предварительный просмотр примера ошибки

2.ClassBad.gif

❎ Примеры ошибок

import React, { Component, PureComponent } from "react";

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  render() {
    const { count } = this.state;
    return (
      <div className="parent">
        <h5>错误示例</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        <Son componentDetails={{ name: "子组件" }} anyMethod={() => {}} />
      </div>
    );
  }
}

class Son extends PureComponent {
  constructor(props) {
    super(props);
  }
  render() {
    const { componentDetails, anyMethod } = this.props;
    console.log("Son -> render -> anyMethod", anyMethod);
    console.log("Son -> render -> componentDetails", componentDetails);
    return <div className="son">{componentDetails?.name}</div>;
  }
}

export { Parent, Son };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

Передача Props в этом примере прямо неверна, почему? Поскольку рендеринг компонента в основном выполняется путем отслеживания изменений реквизитов и состояния, реквизиты, передаваемые в этом примере, каждый раз представляют собой новый объект.Из-за разных ссылок каждый рендеринг родительского компонента будет вызывать рендеринг дочернего компонента.Поэтому повторного рендеринга реальных чисел, вызванного этим написанием, быть не должно! !

Итак, как мы должны написать это?

✅ Правильный пример 1

import React, { Component, PureComponent } from "react";

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      componentDetails: { name: "子组件" },
    };
  }
  handleClick = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };
  anyMethod = () => {};
  render() {
    const { count, componentDetails } = this.state;
    return (
      <div className="parent">
        <h5>正确示例 1</h5>
        <p>父组件Count--{count}</p>
        <button onClick={this.handleClick}>增加</button>
        <Son componentDetails={componentDetails} anyMethod={this.anyMethod} />
      </div>
    );
  }
}

class Son extends PureComponent {
  constructor(props) {
    super(props);
  }
  render() {
    const { componentDetails, anyMethod } = this.props;
    console.log("Son -> render -> anyMethod", anyMethod);
    console.log("Son -> render -> componentDetails", componentDetails);
    return <div className="son">{componentDetails?.name}</div>;
  }
}

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере наш основной правильный способ записи — это прямая передача переменной подкомпоненту, потому что ссылка на переменную та же самая, поэтому послеPureComponent, ссылка не изменилась, что препятствует отрисовке дочернего компонента! !

Объяснение: Строго говоря, этот неправильный пример — это проблема написания метода, что приводит к перерендерингу подкомпонентов, поэтому оптимизации нет, поэтому надо запретить писать код как неправильный пример!

Пример хуков

❎ Предварительный просмотр примера ошибки

2.HooksBad.gif

❎ Примеры ошибок

import { useState, useEffect } from "react";
const Son = ({ componentDetails, anyMethod }) => {
  useEffect(() => {
    console.log("Son -> componentDetails", componentDetails);
  }, [componentDetails]);
  useEffect(() => {
    console.log("Son -> anyMethod", anyMethod);
  }, [anyMethod]);
  return <div className="son">{componentDetails.name}</div>;
};

const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>错误示例</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      <Son componentDetails={{ name: "子组件" }} anyMethod={() => {}} />
    </div>
  );
};

export { Son, Parent };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом неправильном примере это все еще вопрос написания реквизита! ! Далее посмотрим, как это исправить!

✅ Правильный пример 1

import { useState, useEffect } from "react";
const Son = ({ componentDetails, anyMethod }) => {
  useEffect(() => {
    console.log("Son -> componentDetails", componentDetails);
  }, [componentDetails]);
  useEffect(() => {
    console.log("Son -> anyMethod", anyMethod);
  }, [anyMethod]);
  return <div className="son">{componentDetails.name}</div>;
};
// 这种写法 针对于 不变的值 可以这样传递
const componentDetails = { name: "子组件" };
const anyMethod = () => {};

const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };
  return (
    <div className="parent">
      <h5>正确示例1</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      <Son componentDetails={componentDetails} anyMethod={anyMethod} />
    </div>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы просто поместили постоянное значениеупоминается вне компонентаЧтобы убедиться, что ссылка уникальна и не изменится из-за обновлений компонентов. Но этот способ написания имеет определенные ограничения. Он подходит только для неизменяемых значений. Но это также эффективно позволяет избежать повторного рендеринга компонентов.

✅ Правильный пример 2

import { useState, useEffect, useMemo, useCallback } from "react";
const Son = ({ componentDetails, anyMethod }) => {
  useEffect(() => {
    console.log("Son -> componentDetails", componentDetails);
  }, [componentDetails]);
  useEffect(() => {
    console.log("Son -> anyMethod", anyMethod);
  }, [anyMethod]);
  return <div className="son">{componentDetails.name}</div>;
};

const Parent = () => {
  const [count, setCount] = useState(0);
  const handleClick = () => {
    setCount((old) => old + 1);
  };

  const anyMethod = useCallback(() => {}, []);

  const [componentDetails] = useMemo(() => {
    const componentDetails = { name: "子组件" };
    return [componentDetails];
  }, []);

  return (
    <div className="parent">
      <h5>正确示例2</h5>
      <p>父组件Count--{count}</p>
      <button onClick={handleClick}>增加</button>
      <Son componentDetails={componentDetails} anyMethod={anyMethod} />
    </div>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере с помощьюuseCallbackВuseMemoЭти два оптимизированных хука в основном определяют, следует ли обновлять изменение значения в соответствии с изменением зависимости, чтобы гарантировать, что ссылка на значение остается неизменной. Этот метод письма подходит для большинства методов письма, но им не следует злоупотреблять. В противном случае код будет беспорядочным.

Обновления контекста заставляют компонент отображаться

Пример класса

❎ Предварительный просмотр примера ошибки

3.ClassBad.gif

❎ Примеры ошибок

import React, { Component, createContext } from "react";

const contextValue = createContext(undefined);

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      handleIncrement:this.handleIncrement
    };
  }
  handleIncrement = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };

  render() {


    return (
      <contextValue.Provider
        value={this.state}
      >
        <div className="parent">
          <h5>错误示例</h5>
          <Son1 />
          <contextValue.Consumer>
            {(conProps) => <Son2 conProps={conProps} />}
          </contextValue.Consumer>
        </div>
      </contextValue.Provider>
    );
  }
}

class Son1 extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 1 重新渲染了!!");
    return <div className="son">子组件 1</div>;
  }
}

class Son2 extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 2 重新渲染了!!");

    const {
      conProps: { count, handleIncrement },
    } = this.props;
    return (
      <div className="son">
        <p>子组件 2--{count}</p>
        <button onClick={handleIncrement}>增加</button>
      </div>
    );
  }
}

export { Parent };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере внимательно осознайте, что при нажатии кнопки в подкомпоненте 2Что меняется состояние в родительском компонентеИтак, проблема в том, что рендеринг родительского компонента приводит к рендерингу и дочернего компонента. Так как же избежать повторного рендеринга дочерних компонентов?

✅ Правильный пример 1

import React, { Component, createContext } from "react";

const contextValue = createContext(undefined);

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      handleIncrement:this.handleIncrement
    };
  }
  handleIncrement = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };

  render() {
    const { children } = this.props;
    return (
      <contextValue.Provider
        value={this.state}
      >
        <div className="parent">
          <h5>正确示例1</h5>
          {children}
          <contextValue.Consumer>
            {(conProps) => <Son2 conProps={conProps} />}
          </contextValue.Consumer>
        </div>
      </contextValue.Provider>
    );
  }
}

class Son1 extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 1 重新渲染了!!");
    return <div className="son">子组件 1</div>;
  }
}

class Son2 extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 2 重新渲染了!!");

    const {
      conProps: { count, handleIncrement },
    } = this.props;
    return (
      <div className="son">
        <p>子组件 2--{count}</p>
        <button onClick={handleIncrement}>增加</button>
      </div>
    );
  }
}

export { Parent, Son1 };

<Parent>
 <Son1 />
</Parent>

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы по-прежнему заимствуемchildrenМеханизм прямого рендеринга, то есть нет такого понятия как родительский компонент.Ract.createElement(Son)Таким образом, выполнение этого API не вызовет повторного рендеринга!

✅ Правильный пример 2

import React, { Component, createContext, PureComponent } from "react";

const contextValue = createContext(undefined);

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      handleIncrement:this.handleIncrement
    };
  }
  handleIncrement = () => {
    const { count } = this.state;
    this.setState({
      count: count + 1,
    });
  };

  render() {
    return (
      <contextValue.Provider
        value={this.state}
      >
        <div className="parent">
          <h5>正确示例2</h5>
          <Son1 />
          <contextValue.Consumer>
            {(conProps) => <Son2 conProps={conProps} />}
          </contextValue.Consumer>
        </div>
      </contextValue.Provider>
    );
  }
}

class Son1 extends PureComponent {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 1 重新渲染了!!");
    return <div className="son">子组件 1</div>;
  }
}

class Son2 extends PureComponent {
  constructor(props) {
    super(props);
  }
  render() {
    console.log("子组件 2 重新渲染了!!");

    const {
      conProps: { count, handleIncrement },
    } = this.props;
    return (
      <div className="son">
        <p>子组件 2--{count}</p>
        <button onClick={handleIncrement}>增加</button>
      </div>
    );
  }
}

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере в основном заимствованыPureComponentЭтот класс помогает нам выполнять оптимизацию автоматически, избегая повторного рендеринга.

Примечание. Здесь вы также можете принудительно установить React.memo.

Пример хуков

❎ Предварительный просмотр примера ошибки

3.HooksBad.gif

❎ Примеры ошибок

import { createContext, useContext } from "react";
import { useCustomReducer } from "../useCustomizeContext";
const CustomizeContext = createContext(undefined);

const Son1 = () => {
  console.log("子组件1 重新渲染了!!");
  return <div className="son">子组件1</div>;
};
const Son2 = () => {
  const { count, handleIncrement } = useContext(CustomizeContext);
  console.log("子组件2 重新渲染了!!");
  return (
    <div className="son">
      <p>子组件2-{count}</p>
      <button onClick={handleIncrement}>增加</button>
    </div>
  );
};

const Parent = () => {
  const value = useCustomReducer({ initValue: 1 });
  return (
    <CustomizeContext.Provider value={value}>
      <div className="parent">
        <h5>错误示例</h5>
        <Son2 />
        <Son1 />
      </div>
    </CustomizeContext.Provider>
  );
};

export { Son1, Parent, Son2 };

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

используется в этом примереcreateContext, useContext, useReducerЭти API реализуют небольшой Redux. Затем нажмите кнопку в подкомпоненте 2, чтобы изменить значение счетчика, что, в свою очередь, приводит к изменению значения, поэтому родительский компонент визуализируется, вызывая также визуализацию подкомпонента.

✅ Правильный пример 1

import React from "react";
import {
  CustomizeProvider,
  useCustomizeContext,
  useCustomReducer,
} from "../useCustomizeContext";

const Son1 = () => {
  console.log("子组件1 重新渲染了!!");
  return <div className="son">子组件1</div>;
};
const Son2 = () => {
  const { count, handleIncrement } = useCustomizeContext();
  console.log("子组件2 重新渲染了!!");
  return (
    <div className="son">
      <p>子组件2-{count}</p>
      <button onClick={handleIncrement}>增加</button>
    </div>
  );
};

const Parent = ({ children }) => {
  const value = useCustomReducer({ initValue: 1 });
  return (
    <CustomizeProvider value={value}>
      <div className="parent">
        <h5>正确示例1</h5>
        <Son2 />
        {children}
      </div>
    </CustomizeProvider>
  );
};
export { Son1 };
export default Parent;


<Parent>
 <Son1 />
</Parent>

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы по-прежнему используемchildrenдля решения проблемы дублирования рендеринга. Этот метод до сих пор очень эффективен! !

Примечание: На самом деле в проекте должны использоваться соответствующие методы оптимизации!

✅ Правильный пример 2

import React, { memo } from "react";
import {
  CustomizeProvider,
  useCustomizeContext,
  useCustomReducer,
} from "../useCustomizeContext";

const Son1 = () => {
  console.log("子组件1 重新渲染了!!");
  return <div className="son">子组件1</div>;
};
const Son2 = () => {
  const { count, handleIncrement } = useCustomizeContext();
  console.log("子组件2 重新渲染了!!");
  return (
    <div className="son">
      <p>子组件2-{count}</p>
      <button onClick={handleIncrement}>增加</button>
    </div>
  );
};
// 使用 memo
const MemoSon1 = memo(Son1);
const Parent = () => {
  const value = useCustomReducer({ initValue: 1 });
  return (
    <CustomizeProvider value={value}>
      <div className="parent">
        <h5>正确示例2</h5>
        <Son2 />
        <MemoSon1 />
      </div>
    </CustomizeProvider>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

Также используется в этом примереmemoЭтот API, все тот же, сравнивает, изменилась ли ссылка реквизита, и решает, обновлять ли ее.

✅ Правильный пример 3

import React, { useMemo } from "react";
import {
  CustomizeProvider,
  useCustomizeContext,
  useCustomReducer,
} from "../useCustomizeContext";

const Son1 = () => {
  console.log("子组件1 重新渲染了!!");
  return <div className="son">子组件1</div>;
};
const Son2 = () => {
  const { count, handleIncrement } = useCustomizeContext();
  console.log("子组件2 重新渲染了!!");
  return (
    <div className="son">
      <p>子组件2-{count}</p>
      <button onClick={handleIncrement}>增加</button>
    </div>
  );
};

const Parent = () => {
  const value = useCustomReducer({ initValue: 1 });
  return (
    <CustomizeProvider value={value}>
      <div className="parent">
        <h5>正确示例3</h5>
        <Son2 />
        {useMemo(
          () => (
            <Son1 />
          ),
          []
        )}
      </div>
    </CustomizeProvider>
  );
};

export default Parent;

✋🏻 Нажмите, чтобы посмотреть онлайн-демонстрацию

В этом примере мы по-прежнему используемuseMemoЭтот оптимизационный хук используется для оптимизации компонента.

🤙🤙🤙 Резюме

В этой статье представлены методы оптимизации в трех случаях, в основном с использованием:

  • 🤙использоватьпамятку
  • 🤙памятка
  • 🤙дети
  • 🤙использоватьОбратный звонок
  • 🤙PureComponent
  • 🤙 Извлечение компонентов состояния
  • 🤙 Извлечение неизменяемых значений

Эти методы оптимизации можно использовать в разных ситуациях, поэтому, если вы их используете, вы должны использовать соответствующие методы оптимизации в сочетании с ситуацией с кодом.

Если вам известны другие методы оптимизации, вы также можете оставить сообщение в области комментариев! ! !

👏👏👏 Прошедшие моменты