Czy mogę zaktualizować rekwizyty komponentu w React.js?

217

Po rozpoczęciu pracy z React.js wygląda na to, że propsmają być statyczne (przekazywane z komponentu nadrzędnego), a statezmiany oparte na zdarzeniach. Jednak zauważyłem w dokumentach odniesienie componentWillReceiveProps, które konkretnie obejmuje ten przykład:

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

To zdaje się sugerować, że właściwości można zmienić na komponencie w oparciu o porównania nextPropsdo this.props. czego mi brakuje? Jak zmieniają się rekwizyty, czy też mylę się co do tego, jak to się nazywa?

Matt Huggins
źródło

Odpowiedzi:

249

Składnik nie może aktualizować własnych rekwizytów, chyba że są to tablice lub obiekty (posiadanie składnika aktualizującego własne rekwizyty, nawet jeśli jest to możliwe, jest anty-wzorcem), ale może aktualizować swój stan i rekwizyty swoich potomków.

Na przykład pulpit nawigacyjny ma speedpole w swoim stanie i przekazuje je do potomka miernika, który wyświetla tę prędkość. Jego rendermetoda jest sprawiedliwa return <Gauge speed={this.state.speed} />. Gdy panel kontrolny wywołuje this.setState({speed: this.state.speed + 1}), miernik jest renderowany ponownie z nową wartością dla speed.

Tuż przed tym zdarza componentWillReceivePropssię wywoływanie miernika , aby miernik miał szansę porównać nową wartość ze starą.

Valéry
źródło
Brzmi więc tak, jakby był wywoływany raz, gdy składnik React jest inicjowany i otrzymuje rekwizyty. Rekwizyty nie zmieniają się po utworzeniu komponentu. Czy to prawda?
Matt Huggins
12
Przeciwieństwo. Dokumentacja mówi: „wywoływana, gdy składnik odbiera nowe rekwizyty Metoda ta nie jest wymagana wstępna render.”.
Valéry
Dzięki. To pytanie wynikało z początkowego nieporozumienia React polegającego na tym, że komponent zostanie ponownie użyty podczas ponownego wysyłania ekranu (lub jego części).
Matt Huggins
1
Tak. Składnik może nasłuchiwać zdarzenia i aktualizować jego stan przy każdym uruchomieniu zdarzenia.
Valéry,
8
Pochodzę z przyszłości: componentWillReceivePropsjest już przestarzały: i zastąpiony przez kombinację getDerivedStateFromPropsi componentDidUpdate.
bvdb,
53

PROPS

Składnik React powinien używać rekwizytów do przechowywania informacji, które można zmienić, ale można je zmienić tylko za pomocą innego składnika.

STAN

Składnik React powinien używać stanu do przechowywania informacji, które sam składnik może zmienić.

Dobry przykład podał już Valéry.

Ali Adravi
źródło
4
@ali_adravi czy te cytaty są gdzieś kopiowane? Jeśli tak, jakie jest odniesienie? A może to są twoje słowa i właśnie sformatowałeś je jako cytaty dla podkreślenia?
Rob Bednark,
@RobBednark Nie pamiętam teraz dokładnego źródła, ale pewne jest to prawdziwe stwierdzenie z niewielką modyfikacją zdania z jakiejś książki.
Ali Adravi
26

Rekwizyty mogą się zmieniać, gdy element macierzysty komponentu ponownie renderuje komponent z różnymi właściwościami. Myślę, że jest to głównie optymalizacja, więc nie trzeba tworzyć instancji żadnego nowego komponentu.

Joost Diepenmaat
źródło
3

Sztuczka, aby zaktualizować rekwizyty, jeśli są tablicami:

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,
  },
});
Abhishek Kumar
źródło
3
Myślę, że należy unikać inicjalizacji stanu za pomocą rekwizytów. tutaj jest dobry link do przeczytania github.com/vasanthk/react-bits/blob/master/anti-patterns/… .
tryHendri,
0

jeśli używasz recompose, użyj mapPropsdo tworzenia nowych rekwizytów pochodzących z przychodzących rekwizytów

Edytuj na przykład:

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
źródło
podaj przykład
vsync,