Могу ли я обновить реквизиты компонента в React.js?

217

После начала работы с React.js кажется, что он propsдолжен быть статическим (передаваться из родительского компонента), а stateизменения основаны на событиях. Тем не менее, я заметил в документации ссылку componentWillReceiveProps, которая конкретно включает в себя этот пример:

componentWillReceiveProps: function(nextProps) {
  this.setState({
    likesIncreasing: nextProps.likeCount > this.props.likeCount
  });
}

Кажется, это подразумевает, что свойства МОГУТ изменяться для компонента на основе сравнения nextPropsс this.props. Чего мне не хватает? Как меняется реквизит, или я ошибаюсь, откуда это вызывается?

Мэтт Хаггинс
источник

Ответы:

250

Компонент не может обновлять свои собственные реквизиты, если они не являются массивами или объектами (если компонент обновляет свои собственные реквизиты, даже если это возможно, является антишаблоном), но он может обновлять свое состояние и реквизиты своих дочерних элементов.

Например, панель мониторинга имеет speedполе в своем состоянии и передает его дочернему элементу датчика, который отображает эту скорость. Его renderметод справедлив return <Gauge speed={this.state.speed} />. Когда вызывается панель инструментов this.setState({speed: this.state.speed + 1}), датчик повторно отображается с новым значением для speed.

Непосредственно перед тем, как это произойдет, componentWillReceivePropsвызывается Gauge's , так что у Gauge есть шанс сравнить новое значение со старым.

Valéry
источник
Похоже, он вызывается один раз, когда компонент React инициализируется и получает реквизит. Реквизиты на самом деле не «меняются» после создания компонента. Это правильно?
Мэтт Хаггинс
12
Противоположный. Документация говорит: «Вызывается , когда компонент получает новый реквизит Этот метод не вызывается для начального рендеринга..»
Валери
Спасибо. Этот вопрос возник из-за первоначального неправильного понимания React в том, что компонент будет повторно использоваться при повторном отображении экрана (или части экрана).
Мэтт Хаггинс
1
Да. Компонент может прослушивать событие и обновлять свое состояние при каждом срабатывании события.
Валери
8
Я пришел из будущего: componentWillReceivePropsустарел сейчас и заменен комбинацией getDerivedStateFromPropsи componentDidUpdate.
августа,
53

РЕКВИЗИТ

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

ШТАТ

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

Хороший пример уже предоставлен Валери.

Али Адрави
источник
4
@ali_adravi эти цитаты скопированы откуда-то? Если да, то какова ссылка? Или это ваши слова, и вы просто отформатировали их как кавычки?
Роб Беднарк
@RobBednark Я не помню точный источник сейчас, но уверен, что это верное утверждение с небольшим изменением в предложении из какой-то книги.
Али Адрави
26

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

Joost Diepenmaat
источник
3

Хитрость для обновления реквизита, если он является массивом:

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button
} from 'react-native';

class Counter extends Component {
  constructor(props) {
    super(props);
      this.state = {
        count: this.props.count
      }
    }
  increment(){
    console.log("this.props.count");
    console.log(this.props.count);
    let count = this.state.count
    count.push("new element");
    this.setState({ count: count})
  }
  render() {

    return (
      <View style={styles.container}>
        <Text>{ this.state.count.length }</Text>
        <Button
          onPress={this.increment.bind(this)}
          title={ "Increase" }
        />
      </View>
    );
  }
}

Counter.defaultProps = {
 count: []
}

export default Counter
const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});
Абхишек Кумар
источник
3
Я думаю, что инициализация состояния с помощью реквизита является анти-паттерном, следует избегать. Вот хорошая ссылка для чтения github.com/vasanthk/react-bits/blob/master/anti-patterns/… .
TryHendri
0

если вы используете recompose, используйте mapPropsдля создания новых реквизитов, полученных из входящих реквизитов

Редактировать например:

import { compose, mapProps } from 'recompose';

const SomeComponent = ({ url, onComplete }) => (
  {url ? (
    <View />
  ) : null}
)

export default compose(
  mapProps(({ url, storeUrl, history, ...props }) => ({
    ...props,
    onClose: () => {
      history.goBack();
    },
    url: url || storeUrl,
  })),
)(SomeComponent);
ehacinom
источник
приведите пример
vsync