多个React上下文:依赖外部的内部一个不起作用

问题描述 投票:1回答:1

我想为我的应用程序使用2个React Context。

  1. 第一个上下文是UserContext,它加载用户信息。
  2. 第二个上下文是ItemContext,它根据用户ID加载项目信息。

为简单起见,我使用同步函数来加载用户和项目信息。请参阅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是一个空物。

解决办法是什么?

reactjs react-context
1个回答
1
投票

用户值是在UserContext中异步呈现的,并且在子项呈现之前不可用,因此您需要在ItemProvider中实现componentDidUpdate以根据用户道具获取上下文值

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

Working demo

© www.soinside.com 2019 - 2024. All rights reserved.