React.jsでコンポーネントのプロップを更新できますか?


217

React.jsでの作業を開始した後propsstate、イベントに基づいて変更される一方で、静的である(親コンポーネントから渡される)ように意図されているようです。しかし、私はドキュメントでへの参照に気づきましたcomponentWillReceiveProps。これには特にこの例が含まれています。

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

これは、toとの比較に基づいてコンポーネントのプロパティを変更できることを意味しているnextPropsようthis.propsです。何が欠けていますか?小道具はどのように変更されますか、またはこれがどこで呼び出されるのか私は間違っていますか?

回答:


249

コンポーネントは、それらが配列またはオブジェクトでない限り、独自の小道具を更新することはできません(コンポーネントが独自の小道具を更新できるのは、可能な限りアンチパターンです)が、その状態とその子の小道具を更新できます。

たとえば、ダッシュボードのspeed状態にはフィールドがあり、それをこの速度を表示するGaugeの子に渡します。そのrender方法はただreturn <Gauge speed={this.state.speed} />です。ダッシュボードがを呼び出すthis.setState({speed: this.state.speed + 1})と、ゲージはの新しい値で再レンダリングされますspeed

これが発生する直前に、Gauge's componentWillReceivePropsが呼び出されるため、Gaugeは新しい値を古い値と比較する機会があります。


そのため、Reactコンポーネントが初期化され、小道具を受け取っているときに一度呼び出されるようです。コンポーネントが作成されても、プロップは実際には「変更」されません。そうですか?
Matt Huggins

12
反対。ドキュメントは言う:「コンポーネントが新しい小道具を受信しているときに呼び出さ初期レンダリングのためにこのメソッドが呼び出されていません。」
ヴァレリー

ありがとう。この質問は、画面(または画面の一部)を再レンダリングするときにコンポーネントが再利用されるというReactの最初の誤解から来ました。
Matt Huggins

1
はい。コンポーネントはイベントをリッスンし、イベントが発生するたびに状態を更新できます。
ヴァレリー

8
私は未来から来:componentWillReceiveProps今すぐ時代遅れされていますとの組み合わせによって置き換えgetDerivedStateFromPropscomponentDidUpdate
bvdb 2018

53

小道具

Reactコンポーネントは、変更可能な情報を格納するためにプロップを使用する必要がありますが、変更できるのは別のコンポーネントのみです。

状態

Reactコンポーネントは状態を使用して、コンポーネント自体が変更できる情報を格納する必要があります。

良い例はすでにヴァレリーによって提供されています。


4
@ali_adraviそれらの引用はどこからコピーされたのですか?もしそうなら、リファレンスは何ですか?それともあなたの言葉ですか?そして強調のために引用符としてフォーマットしましたか?
Rob Bednark、

@RobBednark私は正確な出典を今は覚えていませんが、本の文章に少し変更を加えた本当の声明であることを確認してください。
Ali Adravi 2018

26

コンポーネントの親がコンポーネントを異なるプロパティで再度レンダリングすると、プロップが変更される可能性があります。これは主に最適化であるため、新しいコンポーネントをインスタンス化する必要はありません。


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 2018年


0

を使用する場合はrecomposemapProps着信プロップから派生した新しいプロップを作成するために使用し ます

たとえば編集:

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

例を
記入して
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.