Стан ініціалізації реакції компонента від реквізиту


204

Чи реальні відмінності між цими двома реалізаціями в React? Деякі друзі кажуть мені, що FirstComponent - це зразок, але я не розумію, чому. SecondComponent здається більш простим, оскільки візуалізація викликається лише один раз.

Перший:

import React, { PropTypes } from 'react'

class FirstComponent extends React.Component {

  state = {
    description: ''
  }

  componentDidMount() {
    const { description} = this.props;
    this.setState({ description });
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} /> 
    );
  }
}

export default FirstComponent;

Друге:

import React, { PropTypes } from 'react'

class SecondComponent extends React.Component {

  state = {
    description: ''
  }

  constructor (props) => {
    const { description } = props;
    this.state = {description};
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} />   
    );
  }
}

export default SecondComponent;

Оновлення: я змінив setState () на this.state = {} (спасибі Джоуз), проте різниці я все ще не бачу. Чи один кращий за інших?


10
Чому ви зберігаєте реквізит у штаті? Ви повинні використовувати реквізит безпосередньо замість цього, а не кешувати значення. Прочитайте, чому встановлення реквізиту як стану в React.js - це богохульство, а реквізити в getInitialState є анти-шаблоном .
Aurora0001

12
Приклад - перемикаючий компонент (наприклад, попова або шухляда). Батько знає, чи повинен компонент починати відкриватися чи закриватися; сам компонент може знати, відкритий він чи ні в певний момент часу. Я вважаю, що в цьому випадку this.state = { isVisible: props.isVisible }є сенс. Залежить від того, як додаток поширює стан інтерфейсу користувача.
Joews

2
Ви повинні прочитати цей media.com/@justintulk/…
FDisk

5
У 2017 році, Facebook демонструє використання реквізиту , щоб встановити початковий стан в своїй документації: reactjs.org/docs/react-component.html#constructor
Rohmer

1
@ Aurora0001 Що з ситуації, коли вам потрібно обробити форму, скажіть форму редагування, яка б самостійно робила мережеві запити, але вам потрібно ініціалізувати вхідні дані зі значеннями, які б стали реквізитом для цього компонента. Щоб зберегти форму динамічною, ці значення потрібно утримувати у стані.
Eric McWinNEr

Відповіді:


196

Слід зазначити, що це анти-шаблон для копіювання властивостей, які ніколи не змінюються до стану (просто в цьому випадку слід отримати доступ до .props). Якщо у вас є змінна стану, яка з часом зміниться, але починається зі значення з .props, ви навіть не потребуєте виклику конструктора - ці локальні змінні ініціалізуються після виклику батьківського конструктора:

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

Це скорочений еквівалент відповіді від @joews нижче. Здається, він працює лише над новішими версіями транспіляторів es6, у мене виникли проблеми з деякими налаштуваннями веб-пакетів. Якщо це не допоможе вам, ви можете спробувати додати плагін Babel babel-plugin-transform-class-properties, або ви можете скористатись некротовою версією @joews нижче.


1
чи можете ви пояснити, чим ваша відповідь відрізняється від відповіді @joews?
Джалал

3
Додано "Ви можете пропустити виклик конструктора, якщо все, що ви робите, це встановлення змінних."
Зейн Хупер

3
Якщо це не працює, вам, ймовірно, потрібно встановити цей плагін Babel "babel-plugin-transform-class-властивості".
Faheem

2
Це не анти-шаблон для ініціалізації стану з реквізиту, якщо розуміється, що стан не покладається на реквізити після ініціалізації. Якщо ви намагаєтеся зберегти два синхронно, це анти-патерн.
Ятрікс

1
@ ak85 - це той самий синтаксис, але ви використовуєте це.state замість цього. Цей синтаксис є лише скороченим синтаксисом для встановлення стану під час процесу побудови класу (і його можна використовувати і для інших змінних, крім стану)
Zane Hooper

137

Вам не потрібно дзвонити setStateв компонент constructor- ідіоматично встановлювати this.stateбезпосередньо:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

Див. Документи React - Додавання локального стану до класу .

Немає переваги першому описаному вами методу. Це призведе до другого оновлення безпосередньо перед монтажем компонента вперше.


4
Хороша відповідь. Можливо, варто зазначити, що це лише для встановлення початкового стану; ви все одно потребуєте використання, setStateякщо ви мутуєте його в будь-який інший момент, інакше зміни можуть не відображатися.
Aurora0001

Ще раз дякую Джоуз, друге документація facebook.github.io/react/docs/…
Леві Морейра

(Вибачте, я натискаю клавішу Enter ..) нам слід використовувати getInitialState для встановлення реквізиту на стан у складніших завданнях, якщо це просто, ми можемо просто використати this.props у візуалізації, правильно?
Леві Морейра

1
На граничній ноті: використання super(props)в конструкторі. Обговорення на SO
cutemachine

2
Пропозиція joews працює в більшості випадків, але будьте обережні, направляючи реквізит безпосередньо до цієї країни. Копіювання реквізиту до цього.state фактично є єдиним джерелом істини ( medium.com/react-ecosystem/… ). Також Дан Абрамов одного разу запропонував не зберігати значення реквізиту в державі. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Хірокі

33

Введено оновлення для React 16.3 альфа static getDerivedStateFromProps(nextProps, prevState)( документи ) в якості заміни componentWillReceiveProps.

getDerivedStateFromProps викликається після екземпляра компонента, а також при отриманні нових реквізитів. Він повинен повернути об’єкт для оновлення стану або нульовим, щоб вказати, що нові реквізити не потребують оновлення стану.

Зауважте, що якщо батьківський компонент викликає повторне відображення вашого компонента, цей метод буде викликаний, навіть якщо реквізити не змінені. Ви можете порівняти нові та попередні значення, якщо ви хочете опрацювати зміни.

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

Він статичний, тому до нього не має прямого доступу this(однак він має доступ до нього prevState, який може зберігати речі, зазвичай прикріплені, thisнаприклад refs)

відредаговано, щоб відобразити виправлення @ нервофолога в коментарях


3
Просто для уточнення, він названий getDerivedStateFromProps(позначте велику літеру в реквізиті), а парами є nextProps, prevState(не nextState): reactjs.org/docs/…
nerfologist

1
Оце Так! ми можемо використовувати це для оновлення стану, коли отримано оновлені реквізити !
Аромал Сасідхаран

2
Чи потрібно ще створити початковий стан у конструкторі, враховуючи, що getDerivedStateFromPropsвиклик завжди викликається перед початковим візуалізацією?
bvdb

19

Ви можете скористатися короткою формою, як показано нижче, якщо ви хочете додати всі реквізити до стану та зберегти ті самі імена.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}

1
це анти-шаблон для копіювання властивостей, які ніколи не змінюються до стану. Краще чітко описати, які поля використовує ваш компонент.
Майкл Фрейджім

5

встановити дані про стан всередині конструктора таким чином

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
  }

він не буде працювати, якщо ви встановите в бічний компонент компонентDidMount () через реквізит.



2

ви можете використовувати keyзначення для скидання стану, коли це потрібно, передайте реквізит, щоб це не є хорошою практикою, оскільки у вас є неконтрольований і контрольований компонент в одному місці. Дані мають бути в одному місці, читайте це https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncont kontroli-component-with- a -кілька


1

Ви можете використовувати компонентWillReceiveProps.

constructor(props) {
    super(props);
    this.state = {
      productdatail: ''
    };
  }

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }

1
компонент
WillReceiveProps

1

Ви повинні бути обережні при ініціалізації stateз propsв конструкторі. Навіть якби було propsзмінено на нове, стан не було б змінено, оскільки кріплення ніколи не повториться. Так getDerivedStateFromPropsіснує для цього.

class FirstComponent extends React.Component {
    state = {
        description: ""
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }

        return null;
    }

    render() {
        const {state: {description}} = this;    

        return (
            <input type="text" value={description} /> 
        );
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.