首页 > 解决方案 > 将组件的层次结构与父级保持状态反应

问题描述

我正在尝试为以下情况创建一个 React SPA:学校 -Student1 -Student2 -Student3 -name -Address - 门牌号、街道、城市、州、国家。

如果我认为,学校,学生,地址作为反应组件。学校:保存/显示学生列表,可以添加、删除。学生:保存/显示信息,例如姓名、地址,可以修改。地址:保存/显示地址详细信息,可以修改。

现在,我如何在这里进行状态管理,比如如果用户修改了其中一名学生的地址,这如何反映在学校中。

我能想到的选项: 1. 使用 Redux,但是说我想创建这个 School 作为组件,将在另一个 React 应用程序中使用,我可以在组件级别使用 Redux 商店吗?

  1. 将Student对象传递给Student react组件,该组件将在修改时使用信息更新.. mutating props。

注意:我是新手,对不起,我写的东西不正确或没有意义。

import * as React from 'react';

export default class School extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      schoolName: "test school",
      students: [],
      update:false
    }
  }

  handleAddStudent = ()=>{
    let student = {
      name : "student1",
      className: "class1",
      address:{
        houseNumber :  "1-2/A-3",
        street: "street1",
        city: "city1",
        country: "country1"
      }
    }
    this.state.students.push(student);
    this.setState({ update: true});
  }

  handleToJson = () => {
    console.log(JSON.stringify(this.state));
  }

  render() {
    return (
    <div>
      <ul>{
        this.state.students.map((student)=>{
            return <Student student={student}/>
        })
      }
      </ul>
      <button onClick={this.handleAddStudent}>Add Student </button>
      <br/>
        <button onClick={this.handleToJson}>To json</button>
    </div>
    );
  }
}

export class Student extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      studentName: this.props.student.name,
      className: this.props.student.className,
      address: this.props.student.address
    }
  }

  handleChange = (e)=>{
    const value = e.target.value;
    switch(e.target.name)
    {
      case 'studentName':
        this.setState({ studentName: value});
        this.props.student.name = value;
        break;
      case 'className':
        this.setState({ className: value });
        this.props.student.className = value;
        break;
    }
  }

  render() {
    return (
      <div>
        <input name='studentName' value={this.state.studentName} onChange={this.handleChange} />
        <input name='className' value={this.state.className} onChange={this.handleChange} />
        <Address name='address' address={this.state.address}/>
      </div>
    );
  }
}

export class Address extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      houseNumber: this.props.address.houseNumber,
      street: this.props.address.street,
      city: this.props.address.city,
      country: this.props.address.country
    }
  }

  handleChange = (e) => {
    const value = e.target.value;
    switch (e.target.name) {
      case 'houseNumber':
        this.setState({ houseNumber: value });
        this.props.address.houseNumber = value;
        break;
      case 'street':
        this.setState({ street: value });
        this.props.address.street = value;
        break;
      case 'city':
        this.setState({ city: value });
        this.props.address.city = value;
        break;
      case 'country':
        this.setState({ country: value });
        this.props.address.country = value;
        break;
    }
  }

  render() {
    return (
      <div>
        <input name='houseNumber' value={this.state.houseNumber} onChange={this.handleChange} />
        <input name='street' value={this.state.street} onChange={this.handleChange} />
        <input name='city' value={this.state.city} onChange={this.handleChange} />
        <input name='country' value={this.state.country} onChange={this.handleChange} />
      </div>
    );
  }
}
<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>

谢谢

标签: reactjsreact-reduxreact-state-management

解决方案


首先,在 React 中使用本地状态很好。一般规则是将状态提升到每个依赖它的组件都可以轻松访问它的级别。如果其中的数据仅对特定组件重要,则将其保留在本地。

现在,我如何在这里进行状态管理,比如如果用户修改了其中一名学生的地址,这如何反映在学校中。

根据您的用例,将学生列表及其属性保留在<School />组件中是最有效的。这样,您可以根据需要将其传递下来,而不必担心。

我注意到你在每个组件中都有本地状态,从它的 props 派生。更有效的做法是简单地创建对道具的引用,然后使用它们。

学校部分(保持原样)

学校应维护学生名单及其所有子资产。

学生和地址组件

这两个应该始终引用它们的 props,并调用父方法来更新状态。

代替

this.state = {
  studentName: this.props.student.name,
  className: this.props.student.className,
  address: this.props.student.address
}

做就是了

const { name, className, address } = this.props.student;

在您需要访问这些变量的任何函数中。

您应该将您的handleX类型函数移动到School中,并通过道具传递它。

您也可以跳过使用太多道具,而只使用Context API。例如...

//In parent

const ThemeContext = React.createContext('default value');

...
return (
  <SchoolContext.Provider value={this.state}>
    ...
  </SchoolContext.Provider>
)
...

//In any child
import Context from './School';

class ChildComponent extends React.Component {
  ...
}

ChildComponent.contextType = Context;

希望能解决这个问题,如果您有不明白的地方,请告诉我。


推荐阅读