В 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 (
       
    );
  }
}

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 (
         
    );
  }
}

export default SecondComponent;

Обновление: Я изменил setState() на this.state = {} (спасибо joews), Однако я все еще не вижу разницы. Может, один вариант лучше другого?

Ответы (9)

Следует отметить, что копирование свойств, которые никогда не меняются, в состояние является антипаттерном (в этом случае достаточно обратиться напрямую к .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, у меня были проблемы с ним на некоторых установках webpack. Если у вас это не работает, вы можете попробовать добавить плагин babel babel-plugin-transform-class-properties, или вы можете использовать версию без сокращений от @joews ниже.

Обновление для React 16.3 alpha представило static getDerivedStateFromProps(nextProps, prevState) (документы) в качестве замены для componentWillReceiveProps.

.

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

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

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

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

.

отредактировано с учетом исправления @nerfologist в комментариях

Вы можете использовать componentWillReceiveProps.

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

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

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

.

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

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

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

установите данные состояния внутри конструктора следующим образом

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

Он не будет работать, если вы установите в боковом методе componentDidMount() через props.

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

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

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

У первого описанного вами метода нет никаких преимуществ. Он приведет к повторному обновлению непосредственно перед установкой компонента в первый раз.

Вы должны быть осторожны при инициализации state из props в конструкторе. Даже если props изменится на новый, состояние не изменится, потому что монтирование никогда не повторится. Поэтому getDerivedStateFromProps существует для этого.

class FirstComponent extends React.Component {
    состояние = {
        описание: ""
    };
    
    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description }
        }
    
        return null;
    }

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

        return (
            
        );
    }
}

Или использовать реквизит key в качестве триггера для инициализации:

class SecondComponent extends React.Component {
  state = {
    // инициализация с помощью props
  };
}

В приведенном выше коде, если something изменилось, то SecondComponent будет перемонтирован как новый экземпляр, а state будет инициализирован props.

2022 WebDevInsider