Компонент React инициализирует состояние из реквизитов


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

первый:

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 () на это.state = {} (спасибо joews), однако, я все еще не вижу разницы. Один лучше другого?

5 74

5 ответов:

следует отметить, что это анти-шаблон для копирования свойств, которые никогда не изменяются в состояние (просто доступ .реквизит прямо в таком случае). Если у вас есть переменная состояния, которая в конечном итоге изменится, но начинается со значения from .реквизит, вам даже не нужен вызов конструктора - эти локальные переменные инициализируются после вызова родительского конструктора:

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, у меня были проблемы с ним на некоторых настройках webpack. Если это не работает для вас, не стенографическая версия от @joews будет.

вам не нужно звонить setState в компоненте constructor - это идиоматично установить this.state напрямую:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

посмотреть реагировать документов - добавление локального состояния на класс.

нет никакого преимущества для первого метода, который вы описываете. Это приведет к второму обновлению непосредственно перед установкой компонента в первый раз.

обновление для React 16.3 Альфа ввел static getDerivedStateFromProps(nextProps, prevState) ( docs) в качестве замены componentWillReceiveProps.

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

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

он статичен, поэтому у него нет прямого доступа к this (однако он имеет доступ к prevState, который может хранить вещи, обычно прикрепленные к this например refs)

отредактировано, чтобы отразить исправление @ nerfologist в комментариях

вы можете использовать короткую форму, как показано ниже, если вы хотите добавить все реквизиты в состояние и сохранить те же имена.

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

Если вы непосредственно инициализируете состояние из реквизита, он будет показывать предупреждение в React 16.5 (5 сентября 2018 года)