отреагировать иерархию компонента на родительское состояние - PullRequest
0 голосов
/ 11 февраля 2019

Я пытаюсь создать React SPA для следующего случая: School -Student1 -Student2 -Student3 -name -Address - номер дома, улица, город, штат, страна.

Если я считаюШкола, Студент, Адрес как реагируют компоненты.Школа: содержит / отображает список учеников, который можно добавлять, удалять.Студент: содержит / отображает информацию, такую ​​как имя, адрес, который можно изменить.Адрес: содержит / отображает детали адреса, которые могут быть изменены.

Теперь, как я могу здесь управлять состоянием, скажем, если пользователь изменяет адрес одного из учеников, как это может отразиться в школе.

вариантов, которые я мог бы придумать: 1. использовать Redux, но я хочу создать эту Школу как компонент, который будет использоваться в другом приложении реагирования, смогу ли я использовать избыточное хранилище на уровне компонентов.

передать объект «Студент» компоненту «Реакция ученика», который при обновлении обновит его информацией. Переменные реквизиты.

Примечание.не имеет смысла.

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>

Спасибо

1 Ответ

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

Во-первых, с использованием локального состояния в React нормально .Общее правило состоит в том, чтобы поднять состояние до уровня, при котором каждый компонент, который опирается на него, будет иметь к нему легкий доступ.Если данные в нем имеют значение только для этого конкретного компонента, то оставьте его локальным.

Теперь, как я могу здесь управлять состоянием, скажем, если пользователь изменяет адрес одного из студентов, как это сделать?это отражено в школе.

Исходя из вашего варианта использования, было бы наиболее эффективно хранить список учащихся и их свойства внутри компонента <School />.Таким образом, вы можете передать его по мере необходимости, не беспокоясь.

Я заметил, что у вас есть состояние локально в каждом компоненте, полученном из его реквизита.Более эффективный способ - просто создать ссылки на реквизит и использовать их вместо этого.

Школьный компонент (оставить как есть)

Школа должна вести списокстудентов, а также все их подвойства.

Компоненты учащегося и адреса

Эти два объекта всегда должны ссылаться на свои реквизиты и вызывать родительский метод для обновления.состояние.

Вместо

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;

Надеюсь, что это прояснилось, дайте мне знать, если есть что-то, что вы не поняли.

...