代码之家  ›  专栏  ›  技术社区  ›  Cannon Moyer

从两个父容器(ReactJS)访问数据

  •  0
  • Cannon Moyer  · 技术社区  · 5 年前

    我有一个组件,可以呈现不同类型的字段,名为 Item . 项目 可能会呈现一个包含以下列表的选择框: Users 或是一份 Inventory .我有两个容器:一个装 用户 还有一个 库存 .我原本想把我的容器放进窝里,但这似乎冻结了我的react应用程序。 Inventories 和 用户 容器是相同的,只是一个容器存放库存物品,另一个容器存放用户。

    这是答案 用户 容器:

    import React, { Component } from 'react';
    
    
     class UsersContainer extends Component{
    
       constructor(props){
         super(props);
         this.state = {
           users: []
         }
    
       }
    
       componentDidMount(){
         //put api call here
         this.setState({users: [{id: 1, name: "Test Name", email: "test@yahoo.com"}, {id: 2, name: "John Doe", email: "johndoe@gmail.com"}, {id: 3, name: "Jane Doe", email: "janedoe@yahoo.com"}]})
       }
    
    
       render(){
         return(
           <div className="users-container">
    
              {React.Children.map(this.props.children, child => (
                   React.cloneElement(child, {...this.props, users: this.state.users })
               ))}
    
           </div>
         )
       }
    
     }
    export default UsersContainer;
    

    我最初尝试将容器嵌套,但这会导致反应冻结:

    <UsersContainer>
        <InventoriesContainer>
            {this.props.items.map(i => (
                <Item name={i.name} />
            ))}
        </InventoriesContainer>
    </UsersContainer>
    

    项目看起来像这样:

    function elementUsesInvetory(inventories){
        //returns selectbox with list of inventory
    }
    
    function elementUsesUsers(users){
        //returns selectbox with list of users
    }
    
    
    function Item(props){
        render(){
    
            return(
                <>
                   {elementUsesUsers(props.inventories)}
                   {elementUsesInventory(props.users)}
                </>
            );
        }
    }
    

    我怎样才能从中提供数据 UsersContainer 和 InventoriesContainer 到 项目 组成部分

    0 回复  |  直到 5 年前
        1
  •  0
  •   Dharman vijay    5 年前

    将它们合并到一个组件中可以避免很多混乱。如果仍要嵌套这些道具,可能需要通过道具钻孔或使用上下文API传递道具。 反应克隆元素 嵌套的子组件不首选。更多信息 here

    您可以借助React的上下文API传递数据。这个 用户容器 组件持有 供应商 和通行证 用户 具体到 库存

    这个 库存 然后将传递给 用户 和 库存 作为电影的道具 项目 组成部分我不确定你是否需要为选择框添加单独的函数,但我已经在演示中添加了它们。

    const MyContext = React.createContext();
    class UsersContainer extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          users: []
        };
      }
    
      componentDidMount() {
        //put api call here
        this.setState({
          users: [
            { id: 1, name: "Test Name", email: "test@yahoo.com" },
            { id: 2, name: "John Doe", email: "johndoe@gmail.com" },
            { id: 3, name: "Jane Doe", email: "janedoe@yahoo.com" }
          ]
        });
      }
    
      render() {
        return (
          <div className="users-container">
            <MyContext.Provider value={this.state.users}>
              {this.props.children}
            </MyContext.Provider>
          </div>
        );
      }
    }
    
    class Inventories extends React.Component {
      static contextType = MyContext;
      constructor(props) {
        super(props);
        this.state = {
          inventories: []
        };
      }
    
      componentDidMount() {
        //put api call here
        this.setState({
          inventories: [
            { id: 1, name: "Test Name", email: "test@yahoo.com" },
            { id: 2, name: "John Doe", email: "johndoe@gmail.com" },
            { id: 3, name: "Jane Doe", email: "janedoe@yahoo.com" }
          ]
        });
      }
    
      render() {
        return (
          <div className="inventory-container">
            {React.Children.map(this.props.children, (child) => {
              return React.cloneElement(child, {
                ...this.props,
                users: this.context,
                inventories: this.state.inventories
              });
            })}
          </div>
        );
      }
    }
    
    function Items(props) {
      function usersSelect(items) {
        return (
          <select>
            {items.map((item) => (
              <option key={"user"+item.id} value="{item.id}">
                {item.name}
              </option>
            ))}
          </select>
        );
      }
    
      function inventoriesSelect(items) {
        return (
          <select>
            {items.map((item) => (
              <option key={item.id} value="{item.id}">
                {item.name}
              </option>
            ))}
          </select>
        );
      }
    
      return (
        <div>
          <h2>users</h2>
          {usersSelect(props.users)}
          <h2>inventories</h2>
          {inventoriesSelect(props.inventories)}
        </div>
      );
    }
    
    
    function App() {
      return (
        <div>
          <UsersContainer>
            <Inventories>
              <Items />
            </Inventories>
          </UsersContainer>
        </div>
      );
    }
    
    ReactDOM.render(<App/>, document.getElementById("root"))
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id="root"></div>
        2
  •  0
  •   iwaduarte    5 年前

    我认为最好的方法是将这些组件之间的状态放在一个 level up 在树组件中。

    那么你想做什么:

    <UsersContainer>
       <InventoriesContainer>
           {this.props.items.map(i => (
                <Item name={i.name} />
            ))}
        </InventoriesContainer>
    </UsersContainer>
    

    将是:

    RealFatherComponent extends Component {
    
    // state that Item will need will be set here
      render() {
        return (
          < UsersContainer **propsShared**  >
            <Item **propsShared** /> 
          </UsersContainer>
          < InventoriesContainer **propsShared** >
            <Item **propsShared** /> );
          </InventoriesContainer>
      }
    }