Reakcja składnika inicjuje stan z rekwizytów

204

Czy w React są jakieś rzeczywiste różnice między tymi dwiema implementacjami? Niektórzy znajomi mówią mi, że FirstComponent jest wzorem, ale nie rozumiem dlaczego. SecondComponent wydaje się prostszy, ponieważ renderowanie jest wywoływane tylko raz.

Pierwszy:

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;

Druga:

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;

Aktualizacja: Zmieniłem setState () na this.state = {} (dzięki joews), Jednak nadal nie widzę różnicy. Czy jedno jest lepsze od drugiego?

Levy Moreira
źródło
10
Dlaczego przechowujesz swoje rekwizyty w stanie? Zamiast tego należy buforować wartość bezpośrednio z rekwizytów. Przeczytaj, dlaczego ustawianie rekwizytów jako stan w React.js to Blasphemy, a rekwizyty w getInitialState to anty-wzorzec .
Aurora0001
12
Przykład - przełączany element (np. Popover lub szuflada). Rodzic wie, czy składnik powinien zacząć otwierać, czy zamykać; sam komponent może wiedzieć, czy w danym momencie jest otwarty, czy nie. W takim przypadku myślę, że this.state = { isVisible: props.isVisible }ma to sens. Zależy od tego, jak aplikacja dystrybuuje stan interfejsu użytkownika.
dołącza
2
Powinieneś przeczytać to medium.com/@justintulk/…
FDisk
5
W 2017 r. Facebook demonstruje używanie rekwizytów do ustawiania stanu początkowego w swojej dokumentacji: reagjs.org/docs/react-component.html#constructor
Rohmer
1
@ Aurora0001 Co z sytuacji, w której musisz obsłużyć formularz, powiedz, że edytuj formularz, który sam wysyła żądania sieciowe, ale musisz zainicjować dane wejściowe wartościami, które byłyby rekwizytami dla tego komponentu. Aby zachować formę dynamiczną, wartości te muszą być utrzymywane w stanie.
Eric McWinNEr

Odpowiedzi:

196

Należy zauważyć, że jest to anty-wzorzec do kopiowania właściwości, które nigdy nie zmieniają się w stan (wystarczy w tym przypadku uzyskać dostęp do .props). Jeśli masz zmienną stanu, która ostatecznie się zmieni, ale zaczyna się od wartości z .props, nie potrzebujesz nawet wywołania konstruktora - te zmienne lokalne są inicjowane po wywołaniu konstruktora rodzica:

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

Jest to skrót odpowiadający odpowiedzi z @joews poniżej. Wydaje się, że działa tylko na nowszych wersjach transpilatorów es6, miałem problemy z niektórymi ustawieniami webpacka. Jeśli to nie zadziała, możesz spróbować dodać wtyczkę babel babel-plugin-transform-class-propertieslub możesz użyć wersji nieskróconej przez @joews poniżej.

Zane Hooper
źródło
1
czy możesz wyjaśnić, czym różni się twoja odpowiedź od odpowiedzi @joews?
Jalal
3
Dodano „Możesz pominąć wywołanie konstruktora, jeśli wszystko, co robisz, to ustawianie zmiennych”.
Zane Hooper,
3
Jeśli to nie działa, prawdopodobnie musisz zainstalować tę wtyczkę Babel „babel-plugin-transform-class-properties”.
Faheem,
2
Inicjalizacja stanu z rekwizytów nie jest anty-wzorcem, jeśli zrozumiemy, że stan nie polega na rekwizytach po inicjalizacji. Jeśli próbujesz zachować synchronizację między nimi, jest to anty-wzorzec.
Yatrix
1
@ ak85 jest to ta sama składnia, ale zamiast tego należy użyć this.state. Ta składnia to tylko skrócona składnia do ustawiania stanu podczas procesu konstruowania klasy (i może być również stosowana do zmiennych innych niż stan)
Zane Hooper
137

Nie musisz wywoływać setStatekomponentu constructor- idiomatyczne jest ustawienie this.statebezpośrednio:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

Zobacz React docs - Dodawanie stanu lokalnego do klasy .

Pierwsza opisana metoda nie ma przewagi. Spowoduje to drugą aktualizację bezpośrednio przed montażem komponentu po raz pierwszy.

joews
źródło
4
Dobra odpowiedź. Warto zauważyć, że służy to jedynie ustawieniu stanu początkowego; nadal musisz go użyć, setStatejeśli zmutujesz go w innym miejscu, w przeciwnym razie zmiany mogą się nie renderować.
Aurora0001
Jeszcze raz dziękuję jowes, drugi dokumentacja facebook.github.io/react/docs/…
Levy Moreira
(przepraszam, naciśnij klawisz Enter). Powinniśmy użyć getInitialState, aby ustawić rekwizyty w stanie, w bardziej złożonych zadaniach, jeśli jest to proste, możemy po prostu użyć this.props do renderowania, prawda?
Levy Moreira,
1
Na marginesie: użyj super(props)w konstruktorze. Dyskusja na temat SO
cutemachine
2
sugestia joews działa w większości przypadków, ale uważaj na bezpośrednie przesyłanie rekwizytów do this.state. Kopiowanie rekwizytów do this.state jest tak naprawdę jednym źródłem prawdy ( medium.com/react-ecosystem/… ). Ponadto Dan Abramov zasugerował kiedyś, aby nie przechowywać w stanie wartości rekwizytów. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki,
33

Aktualizacja dla React 16.3 alfa wprowadzona static getDerivedStateFromProps(nextProps, prevState)( dokumenty ) jako zamiennik componentWillReceiveProps.

getDerivedStateFromProps jest wywoływane po utworzeniu instancji składnika, a także po otrzymaniu nowych rekwizytów. Powinien zwrócić obiekt, aby zaktualizować stan, lub zerowy, aby wskazać, że nowe rekwizyty nie wymagają aktualizacji stanu.

Zauważ, że jeśli komponent nadrzędny powoduje ponowne renderowanie komponentu, ta metoda zostanie wywołana, nawet jeśli rekwizyty się nie zmieniły. Możesz porównać nowe i poprzednie wartości, jeśli chcesz obsłużyć zmiany.

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

Jest statyczny, dlatego nie ma bezpośredniego dostępu do this(jednak ma dostęp do prevState, który mógłby przechowywać rzeczy normalnie dołączone thisnprefs )

edytowane w celu odzwierciedlenia korekty @ nerfologist w komentarzach

Ashley Coolman
źródło
3
Żeby wyjaśnić, jego nazwa getDerivedStateFromProps(oznacz dużą literę w rekwizytach), a paraminextProps: prevState(nie nextState): reaktjs.org/docs/…
nerfologist
1
Łał! możemy użyć tego do aktualizacji stanu, gdy otrzymamy zaktualizowane rekwizyty !
Aromal Sasidharan
2
Czy nadal musimy utworzyć stan początkowy w konstruktorze, biorąc pod uwagę, że getDerivedStateFromPropsjest on zawsze wywoływany przed początkowym renderowaniem?
bvdb
19

Możesz użyć krótkiego formularza jak poniżej, jeśli chcesz dodać wszystkie rekwizyty do stanu i zachować te same nazwy.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
dacharjaya
źródło
1
jest to anty-wzorzec do kopiowania właściwości, które nigdy nie zmieniają się w stan. Lepiej jest wyraźnie opisać, z których pól korzysta twój komponent.
Michael Freidgeim
5

ustaw dane stanu wewnątrz konstruktora w ten sposób

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

nie zadziała, jeśli zostanie ustawiony w bocznej metodzie componentDidMount () za pomocą rekwizytów.

Krishna Kumar Jangid
źródło
3

Jeśli bezpośrednio zainicjujesz stan z rekwizytów, wyświetli ostrzeżenie w React 16.5 (5 września 2018 r.)

Sujith S.
źródło
jakiś pomysł, dlaczego to ostrzeże?
Nitin Jadhav
2
Wygląda na to, że tylko jeśli używasz state = props. Więcej informacji tutaj: github.com/facebook/react/pull/11658#issuecomment-419677176
teraz
1

Możesz użyć componentWillReceiveProps.

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }
Ankit Kumar Rajpoot
źródło
1
componentWillReceiveProps jest przestarzałe, nie można go używać w przyszłych wersjach
Vivek Ghanchi
1

MUSISZ BYĆ OSTROŻNY podczas inicjalizacji statez poziomu propskonstruktora. Nawet jeśli zostanie propszmieniony na nowy, stan nie zostanie zmieniony, ponieważ mount nigdy się nie powtórzy. Tak więc getDerivedStateFromPropsistnieje.

class FirstComponent extends React.Component {
    state = {
        description: ""
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }

        return null;
    }

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

        return (
            <input type="text" value={description} /> 
        );
    }
}
Yonggoo Noh
źródło