отреагировать контекста перерисовывает каждый потомок провайдера - PullRequest
1 голос
/ 04 мая 2020
    import React, { useReducer, useEffect ,Component} from "react";
    import ReactDOM from "react-dom";
    const AppContext = React.createContext();

import React from "react";

const withRandomColors = WrappedComponent => {
  return class RandomColors extends React.Component {
    constructor() {
      super();
      this.randomColors = [
        "red",
        "blue",
        "green",
        "cyan",
        "lavender",
        "skyblue",
        "orange",
        "pink",
        "yellow"
      ];
    }

    getRandomColors() {
      const num = Math.floor(Math.random() * 10) % 9;
      return this.randomColors[num];
    }

    render() {
       console.log("Rerendering wrapper Component");
      return <WrappedComponent randomColor={this.getRandomColors()} />;
    }
  };
};

class Number extends React.Component {
  constructor(props) {
    super(props);
  }

  componentDidMount() {}

  render() {
    console.log("rendering Number Component");
    return (
      <AppContext.Consumer>
        {({ number }) => {
          return (
            <div style={{ backgroundColor: `${this.props.randomColor}` }}>
              {number} <br />
            </div>
          );
        }}
      </AppContext.Consumer>
    );
  }
}

class Text extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
     console.log("rendering Text Component");
    return (
      <AppContext.Consumer>
        {({ text }) => (
          <div style={{ backgroundColor: `${this.props.randomColor}` }}>
            {text} <br />
          </div>
        )}
      </AppContext.Consumer>
    );
  }
}

const WrappedText=withRandomColors(Text);
const WrappedNumber=withRandomColors(Number);

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: Math.random() * 100,
      text: "testing context api"
    };
  }

  updateNumber = () => {
    const randomNumber = Math.random() * 100;
    this.setState({ number: randomNumber });
  };

  render() {
    console.log("rendering app")
    return (
      <AppContext.Provider value={this.state}>
        <div>
          <h1>Welcome to React</h1>
          <WrappedNumber  />
          <WrappedText />
          <button onClick={this.updateNumber}>Change Number </button>
        </div>
      </AppContext.Provider>
    );
  }
}



ReactDOM.render(
  <App />,
  mountNode
);

при нажатии на кнопку ChangeNumber консоль отображает

rendering app

Rerendering wrapper Component

Rerendering Number Component

Rerendering wrapper Component

Rerendering Text Component

и изменения цвета фона как для числа, так и для текста.

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

Я ожидал, что только цифры меняются, при этом цвет фона чисел и текста остается таким же, как и при выводе из консоли после нажатия кнопки «Изменить номер», поскольку предполагается, что только потребители не будут рендериться. компоненты Текст и Число.

rendering app

что мне не хватает?

Я взял код из песочница

1 Ответ

1 голос
/ 04 мая 2020

WrappedNumber и WrappedText повторно визуализируются при обновлении состояния в компоненте приложения, поскольку в Virtual DOM они располагаются в той же иерархии, что и поставщик, и когда родительский компонент обновляет, дочерние компоненты также обновляются.

Чтобы избежать их повторного рендеринга, вы можете предоставить их в качестве дочерних элементов приложения, например

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: Math.random() * 100,
      text: "testing context api"
    };
  }

  updateNumber = () => {
    const randomNumber = Math.random() * 100;
    this.setState({ number: randomNumber });
  };

  render() {
    console.log("rendering app")
    return (
      <AppContext.Provider value={this.state}>
        <div>
          <h1>Welcome to React</h1>
          {this.props.children}
          <button onClick={this.updateNumber}>Change Number </button>
        </div>
      </AppContext.Provider>
    );
  }
}

ReactDOM.render(
  <App >
      <WrappedNumber  />
      <WrappedText />
 </App>,
  mountNode
);
...