【问题标题】:Reactjs -- parent, child - state handling architecture for eachReactjs——父、子——各自的状态处理架构
【发布时间】:2020-01-28 19:37:25
【问题描述】:

我正在开发一个 reactjs 网站,该网站将包含一组项目来填充表格。

父 shell 会将可用记录列表下拉到一个数组中 -- 并使用一个子组件,我想用这些数据填充表格行。

我已经开始创建子组件 - 但是直到我将状态处理放置在渲染函数附近才处理由父组件提供的属性。

我在子组件设置状态中确实有一个构造函数,但它没有看到要走的路——我应该在 componetDidMount 还是 componentWillMount 中设置状态(——如果创建了新的子组件?)

子组件将具有按钮——保存、生成、取消——然后需要更改初始加载状态 -

//规则 父母可以从数组中创建/删除孩子—— 孩子需要获取父母给定的初始值 - 但随后独立于它行事 - 因此孩子可以获取初始属性,然后使用其中的按钮 - 进行自己的调用。应用程序已经被这个父数组绑定,这会导致故障。

-- 孩子需要能够取消 - 例如在保存之前恢复到其原始状态 - 所以如果它被触摸 - isDirty 则为真。 -- 一个老孩子 - isNew: false - 预先存在的数据 - 只显示一个保存按钮。只有名称是可编辑的 -- 一个新的孩子 -- isNew: true -- 首先会显示一个生成按钮(保存隐藏) -- 如果用户手动开始在名称字段中输入数据,生成按钮将被隐藏并显示保存。 -- 在用户选择区域之前,生成/保存按钮将被禁用。

https://codesandbox.io/embed/frosty-vaughan-kdl1v 应该看起来像这样——一旦初始数组生成了孩子——父母应该只能添加空白孩子或删除新/旧孩子——所有其他状态应该只发生在孩子级别——因为你可能有 3 个新孩子,5 个老孩子 - 开始更改值 - 一些被保存,一些被取消 - 独立更改..

父母

import React, { Component } from "react";

import Child from "./Child";
export default class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      list: [
        {
          name: "apple",
          currentCode: "BJ3343",
          previousCode: " ",
          region: "opt2",
          isNew: false,
          isDirty: false
        },
        {
          name: "cherry",
          currentCode: "AS3433",
          previousCode: " ",
          region: "opt1",
          isNew: false,
          isDirty: false
        }
      ]
    };
  }

  addChild() {
    let blank = {
      name: "xxxxxxxxxxxxxxx",
      code: "",
      region: "",
      isNew: true,
      isDirty: true
    };

    this.state.list.push(blank);
  }

  render() {
    return (
      <div>
        <button onClick={this.addChild()}>Add Child</button>
        <button>Remove Child</button>
        <table>
          <thead>
            <tr>
              <td />
              <td>Region</td>
              <td>Code</td>
              <td>Name</td>
              <td>save/generate</td>
              <td>cancel</td>
            </tr>
          </thead>
          <tbody>
            {this.state.list.map((item, index) => {
              return (
                <Child
                  key={index}
                  index={index}
                  item={item}
                />
              );
            })}
          </tbody>
        </table>
      </div>
    );
  }
}

孩子

//import ReactDOM from 'react-dom';
import React, { Component } from "react";

export default class Child extends Component {
  generateCode = index => {
    //does an api call -- and then on success alters the value of the code
    //Make an api call here and suppose api call return code 213
    const responseCode = 231;
    return responseCode;
  };

  saveCode = index => {
    //does an api call -- and then on success makes the child isDirty: false, isNew: false
  };

  cancel = index => {
    //reverts states for this child
  };

  render() {
    const index = this.props.index;
    const { name, region, currentCode, isNew, isDirty } = this.props.item;

    return (
      <tr>
        <td>
          <input type="checkbox" name="selection" />
        </td>
        <td>
          <select disabled={!isNew} type="input" name="region" value={region}>
            <option value="">Select</option>
            <option value="opt1">opt1</option>
            <option value="opt2">opt2</option>
            <option value="opt3">opt3</option>
            <option value="opt4">opt4</option>
          </select>
        </td>
        <td>
          <input disabled={!isNew} type="input" value={currentCode} />{" "}
        </td>
        <td>
          <input type="input" name="name" value={name} />
        </td>
        <td>
          <button onClick={() => this.generateCode(index)}>Generate</button>
          <button onClick={() => this.saveCode(index)}>Save</button>
        </td>

        <td>
          <button onClick={() => this.cancel(index)}>Cancel</button>
        </td>
      </tr>
    );
  }
}

//2019 年 9 月 30 日最新 https://codesandbox.io/embed/elated-raman-twdqr

^ 将添加/删除子节点 -- 为后端删除模拟 db 数组

//2019 年 10 月 1 日最新 https://codesandbox.io/s/stupefied-hodgkin-iyj43 - 最新版本 - 更稳定

【问题讨论】:

  • 为什么你甚至需要孩子的状态?正如 React 开发人员 here 所提到的,从 props 派生状态是一个坏主意。
  • 子组件需要能够修改自己的状态——子组件中会有按钮来进行 api 调用以切换数据内联
  • codesandbox.io/s/stupefied-hodgkin-iyj43 - 最新版本 - 更稳定
  • @TheOldCounty,你能用最新的更新你的问题吗?

标签: reactjs


【解决方案1】:

您需要将状态向上移动到父级并从父级在子级中访问它,如更新的答案所示。更多细节可以在这里找到Lifting up state official reactJS documentation。或者您可以使用集中式状态管理库,例如 reduxmobx

class Parent extends React.Component {
//define your parent as well as child state here. 
state={
  parentState={...},
  childState={name: '', region: ''}
}

handleChange = (newValues) => {
  this.setState({childState: newValues});
  // fetch data here and update it to the state
  fetch(){}
}

componentDidMount(){
  //fetch side effects here like data fecthing and setting state isLoading false here using setState
}

render() {
  if (this.state.isLoading){
    return (
      <p>Loading</p>
    )
  }
  return (
    <div>
      {
        this.state.cart.map((item, key) =>
            <Child key={item.id}
                name=item.name
                region=item.region
                values: {this.state.childState}
                handleChange={this.handleChange}
            />
        );
      }
    </div>
  );
}
}


class Parent extends React.Component {
render() {
  // directly access data using props instead of state
  // pass the updated value upwards to the parent via this.props.handleChange(newValue)(depends on your implementation)
  // Access new value in the child in next render by this.props.childState
  return (
    <div>
      <p>Name: {this.props.values.name}</p>
      <p>Region: {this.props.values.region}</p>
    </div>
  );
}
}

【讨论】:

  • 啊,但是没有——因为孩子们需要能够修改他们自己的道具——所以一旦父母的道具下来——它不仅仅是一个只读的东西。子元素中会有按钮进行 api 调用并内联修改数据
  • 查看更新后的答案,如果它解决了您的问题,请告诉我。
  • 我认为应用程序已经是这样了——这就是问题所在——所有子方面都在一个被复制的庞大数组中处理——它必须是更多的内联操作——其中父母向孩子提供初始状态——但随后孩子可以从那里更新自己的状态——因为他们想要取消(返回旧状态)、保存、生成——那种事情——所以子组件中会有按钮来操作这些。
  • 好吧 - 有没有人开始创建它 - 它是一段非常复杂的代码 - 我正在尝试重构它 - 通过将它分解为一个单独的组件。在罐子上——单击生成按钮将进行调用,然后为子 state.code 获取一个新值——如果你查看我评论过的第一篇文章
  • 这就是我想说的。当您想修改父状态(作为道具传递给孩子)时,请使用handleChange() 函数来修改父状态。更新后的状态将以​​ porps 的形式被孩子接收。子组件不需要有自己的状态。仅将状态保留在父级中阅读我发布的链接
猜你喜欢
  • 2019-01-28
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-02
  • 1970-01-01
  • 2015-04-15
  • 2018-10-05
  • 2015-01-22
相关资源
最近更新 更多