Контекст множественного реагирования: внутренний, зависящий от внешнего, не работает - PullRequest
0 голосов
/ 19 февраля 2019

Я хочу использовать 2 React Context для моего приложения.

  1. Первый контекст - это UserContext, который загружает информацию о пользователе.
  2. Второй контекст - ItemContext, который загружает информацию об элементе на основе идентификатора пользователя.

Для простоты я использую синхронные функции для загрузки информации о пользователе и элементе.См. CodeSandbox для полного рабочего образца.

// index.js

import React from "react";
import ReactDOM from "react-dom";
import { ItemProvider, ItemConsumer } from "./ItemContext";
import { UserProvider, UserConsumer } from "./UserContext";

class App extends React.Component {
  render() {
    return (
      <UserProvider>
        <UserConsumer>
          {({ user }) => (
            <ItemProvider user={user}>
              <ItemConsumer>
                {({ item }) => <div>{JSON.stringify(item, null, 2)}</div>}
              </ItemConsumer>
            </ItemProvider>
          )}
        </UserConsumer>
      </UserProvider>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

// UserContext.js
import React from "react";

const { Provider, Consumer } = React.createContext();

class UserProvider extends React.Component {
  state = {
    isLoading: false,
    value: { user: {} }
  };

  async componentDidMount() {
    this.setState({ isLoading: true });
    const user = { id: 1, name: "evan" };
    this.setState({ value: { user }, isLoading: false });
  }

  render() {
    const { isLoading, value } = this.state;
    if (isLoading) {
      return <div>Loading data...</div>;
    }
    return <Provider value={value}>{this.props.children}</Provider>;
  }
}

export { UserProvider, Consumer as UserConsumer };

// ItemContext.js
import React from "react";

const { Provider, Consumer } = React.createContext();

const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };

const getItemByUserId = userId => items[userId];

class ItemProvider extends React.Component {
  state = {
    isLoading: false,
    value: { item: {} }
  };

  async componentDidMount() {
    this.setState({ isLoading: true });
    const item = getItemByUserId(1);
    // console.log(this.props.user); // Object {}
    // const item = getItemByUserId(this.props.user.id);
    this.setState({ value: { item }, isLoading: false });
  }

  render() {
    const { isLoading, value } = this.state;
    if (isLoading) {
      return <div>Loading data...</div>;
    }
    return <Provider value={value}>{this.props.children}</Provider>;
  }
}

export { ItemProvider, Consumer as ItemConsumer };

Я не могу сделать const item = getItemByUserId(this.props.user.id); в ItemContext, потому что this.props.user - пустой объект.

Какое решение?

1 Ответ

0 голосов
/ 19 февраля 2019

Пользовательское значение отображается изнутри UserContext асинхронно и не будет доступно, пока не будут обработаны дочерние элементы, и, следовательно, вам нужно реализовать componentDidUpdate в ItemProvider, чтобы получить значение контекста, основанное на пропе пользователя

import React from "react";

const { Provider, Consumer } = React.createContext();

const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };

const getItemByUserId = userId => items[userId];

class ItemProvider extends React.Component {
  state = {
    isLoading: false,
    value: { item: {} }
  };

  async componentDidMount() {
    if (this.props.user && this.props.user.id) {
      this.setState({ isLoading: true });
      const item = getItemByUserId(this.props.user.id);
      this.setState({ value: { item }, isLoading: true });
    }
  }

  componentDidUpdate(prevProps) {
    console.log(this.props.user, prevProps.user);
    if (prevProps.user !== this.props.user) {
      const item = getItemByUserId(this.props.user.id);
      this.setState({
        value: { item }
      });
    }
  }

  render() {
    const { isLoading, value } = this.state;
    if (isLoading) {
      return <div>Loading data...</div>;
    }
    console.log(value);
    return <Provider value={value}>{this.props.children}</Provider>;
  }
}

export { ItemProvider, Consumer as ItemConsumer };

Рабочая демоверсия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...