Jak zaktualizować stan rodzica w Reaccie?

Moja struktura wygląda następująco:

Component 1  

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5  

Component 3

Komponent 3 powinien wyświetlać pewne dane w zależności od stanu komponentu 5. Ponieważ właściwości są niezmienne, nie mogę po prostu zapisać jego stanu w komponencie 1 i przesłać go, prawda? I tak, czytałem o reduxie, ale nie chcę go używać. Mam nadzieję, że da się to rozwiązać tylko za pomocą Reacta. Mylę się?

Author: johnborges, 2016-02-21

17 answers

Dla komunikacji dziecko-rodzic powinieneś przekazać funkcję ustawiającą stan z rodzica do dziecka, jak to

class Parent extends React.Component {
  constructor(props) {
    super(props)

    this.handler = this.handler.bind(this)
  }

  handler() {
    this.setState({
      someVar: 'some value'
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {this.props.handler}/ >
  }
}

W ten sposób dziecko może zaktualizować stan rodzica wywołaniem funkcji przekazanej z właściwościami.

Ale będziesz musiał przemyśleć strukturę swoich komponentów, ponieważ jak rozumiem Składniki 5 I 3 nie są ze sobą powiązane.

Jednym z możliwych rozwiązań jest zawinięcie ich w komponent wyższego poziomu, który będzie zawierał stan obu komponent 1 i 3. Ten komponent ustawi stan niższego poziomu za pomocą właściwości.

 763
Author: Ivan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-04 23:07:57

Znalazłem następujące rozwiązanie do przekazania argumentu funkcji onclick z potomka do komponentu nadrzędnego:

Wersja z przekazaniem metody()

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div><button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component {

    constructor(props) {
        super(props);
        var handleToUpdate  = this.handleToUpdate.bind(this);
        var arg1 = '';
    }

    handleToUpdate(someArg){
            alert('We pass argument from Child to Parent: ' + someArg);
            this.setState({arg1:someArg});
    }

    render() {
        var handleToUpdate  =   this.handleToUpdate;

        return (<div>
                    <ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

Spójrz na JSFIDDLE

Wersja z funkcją Strzałki

//ChildB component
class ChildB extends React.Component {

    render() {

        var handleToUpdate  =   this.props.handleToUpdate;
        return (<div>
          <button onClick={() => handleToUpdate('someVar')}>
            Push me
          </button>
        </div>)
    }
}

//ParentA component
class ParentA extends React.Component { 
    constructor(props) {
        super(props);
    }

    handleToUpdate = (someArg) => {
            alert('We pass argument from Child to Parent: ' + someArg);
    }

    render() {
        return (<div>
            <ChildB handleToUpdate = {this.handleToUpdate} /></div>)
    }
}

if(document.querySelector("#demo")){
    ReactDOM.render(
        <ParentA />,
        document.querySelector("#demo")
    );
}

Spójrz na JSFIDDLE

 53
Author: Roman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-10 17:27:51

Chcę podziękować najbardziej upvoted odpowiedzi za danie mi pomysł mojego własnego problemu w zasadzie odmiany go z funkcji Strzałki i przekazywanie param z komponentu potomnego:

 class Parent extends React.Component {
  constructor(props) {
    super(props)
    // without bind, replaced by arrow func below
  }

  handler = (val) => {
    this.setState({
      someVar: val
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <Button onClick = {() => this.props.handler('the passing value')}/ >
  }
}
Mam nadzieję, że to komuś pomoże.
 15
Author: Ardhi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-07 05:53:47

Podoba mi się odpowiedź dotycząca przekazywania funkcji, to bardzo przydatna technika.

Z drugiej strony można to również osiągnąć używając pub/sub lub używając wariantu, dyspozytora, tak jak robi to Flux. Teoria jest bardzo prosta, niech komponent 5 wyśle wiadomość, której komponent 3 słucha. Komponent 3 aktualizuje swój stan, który uruchamia ponowne renderowanie. Wymaga to elementów stateful, które w zależności od punktu widzenia mogą lub nie mogą być anty-wzorcem. Jestem przeciw oni osobiście i woleliby, żeby coś innego nasłuchiwało depeszy i zmieniało stan z góry na dół (Redux to robi, ale dodaje dodatkową terminologię).

import { Dispatcher } from flux
import { Component } from React

const dispatcher = new Dispatcher()

// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
  state = {
    text: 'foo'
  } 

  componentDidMount() {
    dispatcher.register( dispatch => {
      if ( dispatch.type === 'change' ) {
        this.setState({ text: 'bar' })
      }
    }
  }

  render() {
    return <h1>{ this.state.text }</h1>
  }
}

// Click handler
const onClick = event => {
  dispatcher.dispatch({
    type: 'change'
  })
}

// Component 5 in your example
const StatelessChild = props => {
  return <button onClick={ onClick }>Click me</button> 
}

Pakiety dispatchera z Flux są bardzo proste, po prostu rejestruje wywołania zwrotne i wywołuje je, gdy dojdzie do jakiejkolwiek wysyłki, przechodząc przez zawartość w dispatcherze (w powyższym przykładzie nie ma payload z dispatcherem, po prostu id wiadomości). Można to dostosować do tradycyjnego pub/sub (np. korzystanie z EventEmitter z events, lub innej wersji) bardzo łatwo, jeśli ma to dla Ciebie większy sens.

 9
Author: Matt Styles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-21 15:18:43

Znalazłem następujące rozwiązanie do przekazania argumentu funkcji onclick z potomka do komponentu nadrzędnego z param:

Klasa nadrzędna:

class Parent extends React.Component {
constructor(props) {
    super(props)

    // Bind the this context to the handler function
    this.handler = this.handler.bind(this);

    // Set some state
    this.state = {
        messageShown: false
    };
}

// This method will be sent to the child component
handler(param1) {
console.log(param1);
    this.setState({
        messageShown: true
    });
}

// Render the child component and set the action property with the handler as value
render() {
    return <Child action={this.handler} />
}}

Klasa dziecka:

class Child extends React.Component {
render() {
    return (
        <div>
            {/* The button will execute the handler function set by the parent component */}
            <Button onClick={this.props.action.bind(this,param1)} />
        </div>
    )
} }
 9
Author: H. parnian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-23 18:11:52

Jeśli kiedykolwiek chcesz komunikować się między dzieckiem a rodzicem na dowolnym poziomie w dół, lepiej jest użyćkontekstu . W komponencie nadrzędnym zdefiniuj kontekst, który może być wywołany przez potomka, taki jak

W komponencie nadrzędnym w Twoim przypadku komponent 3

static childContextTypes = {
        parentMethod: React.PropTypes.func.isRequired
      };

       getChildContext() {
        return {
          parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
        };
      }

parentMethod(parameter_from_child){
// update the state with parameter_from_child
}

Teraz w komponencie potomnym (komponent 5 w Twoim przypadku), po prostu powiedz to komponent, który chce użyć kontekstu swojego rodzica.

 static contextTypes = {
       parentMethod: React.PropTypes.func.isRequired
     };
render(){
    return(
      <TouchableHighlight
        onPress={() =>this.context.parentMethod(new_state_value)}
         underlayColor='gray' >   

            <Text> update state in parent component </Text>              

      </TouchableHighlight>
)}

Możesz znaleźć projekt Demo na repo

 5
Author: Rajan Twanabashu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-20 06:47:26

Wydaje się, że możemy przekazywać dane tylko z rodzica do dziecka, ponieważ react Promuje jednokierunkowy przepływ danych, ale aby rodzic się aktualizował, gdy coś dzieje się w jego "komponencie potomnym", zwykle używamy tzw. "funkcji zwrotnej".

Przekazujemy dziecku funkcję zdefiniowaną w rodzicu jako "props" i wywołaj tę funkcję od dziecka wyzwalającego ją w rodzicu komponent.


class Parent extends React.Component {
  handler = (Value_Passed_From_SubChild) => {
    console.log("Parent got triggered when a grandchild button was clicked");
    console.log("Parent->Child->SubChild");
    console.log(Value_Passed_From_SubChild);
  }
  render() {
    return <Child handler = {this.handler} />
  }
}
class Child extends React.Component {
  render() {
    return <SubChild handler = {this.props.handler}/ >
  }
}
class SubChild extends React.Component { 
  constructor(props){
   super(props);
   this.state = {
      somethingImp : [1,2,3,4]
   }
  }
  render() {
     return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
  }
}
React.render(<Parent />,document.getElementById('app'));

 HTML
 ----
 <div id="app"></div>

W tym przykładzie możemy przekazać dane z SubChild - > Child - > Parent przekazując funkcję do bezpośredniego dziecka.

 4
Author: Vishal Bisht,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-23 02:15:52

-możemy wytworzyć ParentComponent oraz przy pomocy metody handleInputChange zaktualizować stan ParentComponent. Importujemy komponent potomny i przekazujemy dwie właściwości z komponentu rodzica do komponentu potomnego tj.funkcja handleInputChange I count.

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  constructor(props) {
    super(props);
    this.handleInputChange = this.handleInputChange.bind(this);
    this.state = {
      count: '',
    };
  }

  handleInputChange(e) {
    const { value, name } = e.target;
    this.setState({ [name]: value });
  }

  render() {
    const { count } = this.state;
    return (
      <ChildComponent count={count} handleInputChange={this.handleInputChange} />
    );
  }
}
  • Teraz tworzymy plik ChildComponent i zapisujemy jako ChildComponent.jsx. Komponent ten jest bezstanowy, ponieważ komponent potomny nie ma stanu. Używamy biblioteki props-types do sprawdzania typu props.

    import React from 'react';
    import { func, number } from 'prop-types';
    
    const ChildComponent = ({ handleInputChange, count }) => (
      <input onChange={handleInputChange} value={count} name="count" />
    );
    
    ChildComponent.propTypes = {
      count: number,
      handleInputChange: func.isRequired,
    };
    
    ChildComponent.defaultProps = {
      count: 0,
    };
    
    export default ChildComponent;
    
 3
Author: Sachin Metkari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-06 10:16:55

Wielokrotnie korzystałem z najwyżej ocenianej odpowiedzi z tej strony, ale podczas nauki Reacta znalazłem lepszy sposób, aby to zrobić, bez wiązania i bez funkcji inline wewnątrz rekwizytów.

Spójrz tutaj:

class Parent extends React.Component {

  constructor() {
    super();
    this.state={
      someVar: value
    }
  }

  handleChange=(someValue)=>{
    this.setState({someVar: someValue})
  }

  render() {
    return <Child handler={this.handleChange} />
  }

}

export const Child = ({handler}) => {
  return <Button onClick={handler} />
}

Klawisz znajduje się w funkcji strzałki:

handleChange=(someValue)=>{
  this.setState({someVar: someValue})
}

Możesz przeczytać więcej tutaj . Mam nadzieję, że to się komuś przyda=)

 3
Author: Александр Немков,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-11 18:58:13

Jeśli ten sam scenariusz nie jest rozpowszechniony wszędzie, możesz użyć kontekstu Reacta, szczególnie jeśli nie chcesz wprowadzać wszystkich kosztów, które wprowadzają biblioteki zarządzania stanem. Poza tym łatwiej się tego nauczyć. Ale bądź ostrożny, możesz go nadużywać i zacząć pisać zły kod. Zasadniczo definiujesz komponent kontenera (który będzie przechowywał i zachowywał dla Ciebie ten fragment stanu), dzięki czemu wszystkie komponenty zainteresowane zapisem / odczytaniem tego fragmentu danych są jego potomkami (niekoniecznie bezpośrednio dzieci)

Https://reactjs.org/docs/context.html

Możesz również użyć zwykłego Reacta poprawnie.

<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />

Przekaż doSomethingAbout5 do komponentu 1

    <Component1>
        <Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
        <Component5 propThatDependsOn5={this.state.somethingAbout5}/>
    <Component1/>

Jeśli jest to częsty problem, powinieneś zacząć myśleć o przeniesieniu całego stanu aplikacji w inne miejsce. Masz kilka opcji, najczęściej są to:

Https://redux.js.org/

Https://facebook.github.io/flux/

Zasadniczo, zamiast aby zarządzać stanem aplikacji w komponencie, wysyłasz polecenia, gdy coś się stanie, aby uaktualnić stan. Komponenty również pobierają stan z tego kontenera, dzięki czemu wszystkie dane są scentralizowane. Nie oznacza to, że nie można już używać stanu lokalnego, ale jest to bardziej zaawansowany temat.

 2
Author: Pato Loco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-04 14:11:16

Większość powyższych odpowiedzi jest dla Reacta.Projekty oparte na komponentach. Jeśli używasz useState W ostatnich aktualizacjach Biblioteki Reacta, wykonaj tę odpowiedź

 2
Author: leeCoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-06 03:57:12

Więc, jeśli chcesz zaktualizować komponent nadrzędny,

 class ParentComponent extends React.Component {
        constructor(props){
            super(props);
            this.state = {
               page:0
            }
        }

        handler(val){
            console.log(val) // 1
        }

        render(){
          return (
              <ChildComponent onChange={this.handler} />
           )
       }
   }


class ChildComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
             page:1
        };
    }

    someMethod = (page) => {
        this.setState({ page: page });
        this.props.onChange(page)
    }

    render() {
        return (
       <Button
            onClick={() => this.someMethod()} 
       > Click
        </Button>
      )
   }
}

Tutaj onChange jest atrybutem z metodą" handler " związaną z jego instancją. przekazaliśmy obsługę metody do komponentu klasy potomnej, aby otrzymać poprzez właściwość onChange w jej argumencie właściwości.

Atrybut onChange zostanie ustawiony w obiekcie właściwości, takim jak:

props ={
onChange : this.handler
}

I przekazywane do komponentu potomnego

Aby komponent potomny mógł uzyskać dostęp do wartości name w obiekcie właściwości w następujący sposób rekwizyty.onChange

Jego wykonanie odbywa się za pomocą rekwizytów renderujących.

Teraz komponent potomny ma przycisk "Click" z ustawionym zdarzeniem onclick, aby wywołać metodę obsługi przekazaną mu przez onChnge w jego obiekcie argumentu props. A teraz to.rekwizyty.onChange in Child przechowuje metodę wyjściową w klasie rodzica odniesienia i kredyty: bity i kawałki

 1
Author: Preetham NT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-15 15:22:40

Możemy ustawić stan rodzica z komponentu potomnego przekazując funkcję do komponentu potomnego jako właściwości jak poniżej

class Parent extends React.Component{
    state = { term : ''}

     onInputChange = (event)=>{
         this.setState({term: event.target.value});
     }

     onFormSubmit= (event)=>{
         event.preventDefault();
         this.props.onFormSubmit(this.state.term);
     }

     render(){
         return (
             <Child onInputChange={this.onInputChange} onFormSubmit= 
                {this.onFormSubmit} />
         )
     }
}

   
class Child extends React.Component{

     render(){
        return (
             <div className="search-bar ui segment">
                 <form className="ui form" onSubmit={this.props.onFormSubmit}>
                    <div class="field">
                      <label>Search Video</label>
                      <input type="text" value={this.state.term} onChange= 
                           {this.props.onInputChange} />
                    </div>
                    
                 </form>
             </div>
         )
     }
}

W ten sposób dziecko zaktualizuje stan rodzica oninputchange i onFormSubmit są rekwizytami przekazanymi od rodziców. To może być wywołane jako i event Listeners w Child,stąd stan zostanie tam zaktualizowany

 1
Author: Athul Narayanan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-13 14:56:06

Tak to robię.

type ParentProps = {}
type ParentState = { someValue: number }
class Parent extends React.Component<ParentProps, ParentState> {
    constructor(props: ParentProps) {
        super(props)
        this.state = { someValue: 0 }

        this.handleChange = this.handleChange.bind(this)
    }

    handleChange(value: number) {
        this.setState({...this.state, someValue: value})
    }

    render() {
        return <div>
            <Child changeFunction={this.handleChange} defaultValue={this.state.someValue} />
            <p>Value: {this.state.someValue}</p>
        </div>
    }
}

type ChildProps = { defaultValue: number, changeFunction: (value: number) => void}
type ChildState = { anotherValue: number }
class Child extends React.Component<ChildProps, ChildState> {
    constructor(props: ChildProps) {
        super(props)
        this.state = { anotherValue: this.props.defaultValue }

        this.handleChange = this.handleChange.bind(this)
    }

    handleChange(value: number) {
        this.setState({...this.state, anotherValue: value})
        this.props.changeFunction(value)
    }

    render() {
        return <div>
            <input onChange={event => this.handleChange(Number(event.target.value))} type='number' value={this.state.anotherValue}/>
        </div>
    }
}
 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-07 13:15:21

Jak na twoje pytanie, rozumiem, że musisz wyświetlić niektóre dane warunkowe w komponencie 3, który jest oparty na stanie komponentu 5. "Podejście": {]}

  1. Stan komponentu 3 będzie przechowywał zmienną, aby sprawdzić, czy stan komponentu 5 ma te dane
  2. Funkcja strzałki, która zmieni zmienną stanu komponentu 3.
  3. przekazanie funkcji strzałki do komponentu 5 za pomocą rekwizytów.
  4. komponent 5 ma funkcję strzałki, która zmieni stan komponentu 3 zmienna
  5. Funkcja Strzałki komponentu 5 wywołana przy samym ładowaniu

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Class Component3 extends React.Component {
    state = {
        someData = true
    }

    checkForData = (result) => {
        this.setState({someData : result})
    }

    render() {
        if(this.state.someData) {
            return(
                <Component5 hasData = {this.checkForData} />
                //Other Data
            );
        }
        else {
            return(
                //Other Data
            );
        }
    }
}

export default Component3;

class Component5 extends React.Component {
    state = {
        dataValue = "XYZ"
    }
    checkForData = () => {
        if(this.state.dataValue === "XYZ") {
            this.props.hasData(true);
        }
        else {
            this.props.hasData(false);
        }
    }
    render() {
        return(
            <div onLoad = {this.checkForData}>
                //Conditional Data
            </div>
        );
    }
}
export default Component5;
 0
Author: Vikram Dhanwani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-13 14:15:46

Tak możemy to zrobić z nowym useState hakiem. Method-przekazać funkcję zmieniacza stanu jako właściwość komponentowi potomnemu i zrobić wszystko, co chcesz zrobić z funkcją

import React, {useState} from 'react';

const ParentComponent = () => {
  const[state, setState]=useState('');
  
  return(
    <ChildConmponent stateChanger={setState} />
  )
}


const ChildConmponent = ({stateChanger, ...rest}) => {
  return(
    <button onClick={() => stateChanger('New data')}></button>
  )
}
 0
Author: moshfiqrony,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-13 14:27:23
<Footer 
  action={()=>this.setState({showChart: true})}
/>

<footer className="row">
    <button type="button" onClick={this.props.action}>Edit</button>
  {console.log(this.props)}
</footer>

Try this example to write inline setState, it avoids creating another function.
 -4
Author: suresh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-05 17:09:12