Кто-нибудь знает более простой способ написать этот код в ReactJS - PullRequest
0 голосов
/ 13 февраля 2019

Я смотрел React Tutorial, и инструктор не очень хорошо объяснил мне часть.В основном он пытался научить динамически отображать список в трех разных полях ввода.Все, что напечатано в каждом поле ввода, будет отображаться в соответствующем элементе div над ним.И инструктор сказал нам, что мы не должны напрямую касаться состояния, в котором этот код усложняется.Есть ли более простой способ написать этот код?Не понимаю его.Код, который инструктировал инструктор, находится в функции nameChangeHandler .Пожалуйста, смотрите код ниже.Спасибо!

import React, { Component } from 'react';
import './App.css';
import Person from "./Person/Person"

class App extends React.Component {

  state={
    persons: [
      {id: 1,name: "Max", age:28 },
      {id:2,name: "Manu", age: 29},
      {id:3, name: "Stephanie", age: 26 }
    ],
    showPersons: false
  }

  deletePersonHandler=(index)=> {
   const persons = [...this.state.persons];
   persons.splice(index, 1)
   this.setState({ persons: persons});
   console.log(persons)
  }

  nameChangedHandler = (e, id ) => {
    const personIndex = this.state.persons.findIndex(p=> {
      return p.id === id;
    })

    const person = {
      ...this.state.persons[personIndex]
    };

    person.name= e.target.value;

    const persons = [...this.state.persons];
    persons[personIndex] = person;

    this.setState({
      persons: persons
    })

  }

  togglePersonsHandler=()=> {
    const showing = this.state.showPersons;
    this.setState({ showPersons: !showing })
  }


  render() {

    const style={
      backgroundColor: "white",
      font:"inherit",
      border:"1px solid blue",
      padding:"8px",
      cursor:"pointer"
    }

    let persons=null;
    if(this.state.showPersons) {
      persons=(
      <div>
        {this.state.persons.map((person, index)=> {
          return(
            <Person 
              key={person.id}
              changed={(e)=>this.nameChangedHandler(e, person.id)}
              click={()=>this.deletePersonHandler(index)}
              name={person.name} 
              age={person.age}/>
          )
        })}
      </div>)
    }
    return (
      <div className="App">
        <h1>Hi, Im a React App</h1>
        <p>This is really working!!!</p>
        <button style={style} onClick={this.togglePersonsHandler}>Toggle Persons</button>
        {persons}
      </div>
    );
  }
}

export default App;

Image of my app

Ответы [ 2 ]

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

В соответствии с вашим запросом в комментариях приведено краткое объяснение этого кода:

nameChangedHandler = (e, id ) => {
  const personIndex = this.state.persons.findIndex(p=> {
    return p.id === id;
  })

То, что вы видите, это функция стрелки .В целях всего этого ответа рассматривайте их как нормальную функцию (это не то же самое, однако это можно сделать и с обычными функциями).Семантически говоря, функции стрелок или обычные функции не меняют то, что делает код / ​​его намерения, поэтому я не буду вдаваться в подробности, вы просто должны знать, что вы видите.Если вы не знакомы с ними, вы должны прочитать об этом, они очень полезны.Подпись для функции стрелки: (a,b) => {}, a => {} или a => <expression>.Таким образом, грубо говоря, вышеприведенное можно логически интерпретировать как function(e,id){} и function(p){}, просто чтобы прояснить это до того, как я продолжу (это не сработает, если будет написано таким образом, но это сообщение, которое оно передает).Сам код извлекает индекс человека, который соответствует параметру id, который вы передали nameChangeHandler.Это делается с помощью findIndex , функции, которая перебирает массив (в данном случае массив .persons вашего состояния) и возвращает индекс первого элемента, который проходит заданную тестовую функцию.Этот индекс затем сохраняется внутри переменной для последующего использования в коде.

Значения

e и id получены в результате вызова самой функции, я не могу дать вам большеподробно, так как я не вижу, что такое класс <Person>, но можно с уверенностью предположить, что этот обработчик присоединяется к полю ввода.Как только изменение произойдет с помощью обработчика onChange в поле ввода, реагирование вызовет обработчик и передаст ему event, содержащий данные события.Ваш обработчик на самом деле не функция nameChangeHandler, это функция стрелки, которая принимает event e, а затем вызывает nameChangeHandler, передавая как event e, так и id для человека, вы можете видетьчто здесь changed={(e)=>this.nameChangedHandler(e, person.id)}.Остальные значения считываются из вашего state.

Давайте продолжим с кодом:

const person = {
  ...this.state.persons[personIndex]
};

То, что мы здесь имеем, называется распространения .По сути, он «распаковывает и перепаковывает» объект или массив, вы можете узнать больше об этом по данной ссылке MDN.Это новая мощная функция ES6, которая делает жизнь намного проще.

Таким образом, приведенный выше код используется для умного поверхностного копирования объекта персонажа из массива в новую локальную переменную (или, скорее, const, поскольку переменная подразумевает возможность изменения)Мы делаем это потому, что в javascript данные объекта хранятся по ссылке, поэтому мы не можем просто изменить объект person внутри исходного массива, который бы изменял состояние.Мы не хотим мутировать государство.Ключ неизменен.

person.name= e.target.value;

После этого у нас простое назначение.Новый объект person, который мы только что создали, является точной (своего рода) копией того, кем был человек внутри массива .persons государства, и это нехорошо, мы хотим изменить имя, поэтому мы делаем именно это.Мы получаем доступ к event e и читаем value из target, который его вызвал, назначаем новое значение нашему person объекту, и теперь у нас есть «измененный человек» (каламбур предназначен).

Нам осталось только перенести эти изменения в состояние, чтобы новый рендер мог их показать, поэтому мы делаем:

const persons = [...this.state.persons];
persons[personIndex] = person;

Этот код снова использует распространение клонировать / копировать старый массив из состояния в новый локальный массив person.Это эквивалентно использованию const persons = this.state.persons.slice().Вы можете прочитать больше о .slice() на MDN (намеренно не оставляя прямой ссылки для вас, чтобы вы ее искали и изучали эту часть, MDN действительно отличный источник для документации всех видови знакомство с этим сайтом - спасение жизни.)Наконец, после того, как массив клонирован, мы находим оригинального человека и заменяем его на локальный объект персоны, у которого есть измененное имя.

this.setState({
  persons: persons
})

Наконец, мы используем метод .setState, который реагирует (см. документация ) для неизменного изменения состояния.Это изменение вызовет новый render(), и вы сможете увидеть изменения в пользовательском интерфейсе.Сам .setState() работает, выполняя поверхностное слияние .Это означает, что только свойства, которые вы передаете самому методу, будут изменены / добавлены в состояние, остальные свойства будут сохранены, как есть.Поскольку единственное, что мы передаем, это другой массив persons, который является нашим локальным массивом, с измененным человеком, это единственное, что изменяется.

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

При обновлении локального состояния, основываясь на текущем локальном состоянии, вы должны использовать шаблон обратного вызова setState, потому что React объединяет вызовы this.setState.

Кроме того, мелкое копирование и обновлениеотлично, но вы также можете использовать стандартный метод Array.prototype.map для обновления:

nameChangedHandler = (e, id ) => {
  this.setState((prevState) => {
     const persons = prevState.persons.map(person, i => {
       return i === id ? { ...person, name: e.target.name } : person;
     });

    return {
      persons: persons,
    };
  });     
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...