Jak przekazać dane z komponentu podrzędnego do jego elementu nadrzędnego w ReactJS?

211

Próbuję wysłać dane z elementu potomnego do jego elementu nadrzędnego w następujący sposób:

const ParentComponent = React.createClass({
    getInitialState() {
        return {
            language: '',
        };
    },
    handleLanguageCode: function(langValue) {
        this.setState({language: langValue});
    },

    render() {
         return (
                <div className="col-sm-9" >
                    <SelectLanguage onSelectLanguage={this.handleLanguage}/> 
                </div>
        );
});

a tutaj jest element potomny:

export const SelectLanguage = React.createClass({
    getInitialState: function(){
        return{
            selectedCode: '',
            selectedLanguage: '',
        };
    },

    handleLangChange: function (e) {
        var lang = this.state.selectedLanguage;
        var code = this.state.selectedCode;
        this.props.onSelectLanguage({selectedLanguage: lang});   
        this.props.onSelectLanguage({selectedCode: code});           
    },

    render() {
        var json = require("json!../languages.json");
        var jsonArray = json.languages;
        return (
            <div >
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    value={this.state.selectedLanguage}
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
});

Potrzebuję uzyskać wybraną wartość przez użytkownika w komponencie nadrzędnym. Otrzymuję ten błąd:

Uncaught TypeError: this.props.onSelectLanguage is not a function

Czy ktoś może mi pomóc znaleźć problem?

PS Komponent potomny tworzy listę rozwijaną z pliku json i potrzebuję listy rozwijanej, aby wyświetlić oba elementy tablicy json obok siebie (na przykład: „aaa, angielski” jako pierwszy wybór!)

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}
Birish
źródło
3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> literówka.
Yury Tarabanko
@YuryTarabanko Dzięki, ale wciąż pojawia się ten sam błąd
Birish
@DavinTryon Jak dodać? Próbowałem w ten sposób: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },Ale zwraca błąd:ncaught TypeError: Cannot read property 'bind' of undefined
Birish
2
@DavinTryon automatycznie createClassrozpoznaje metody niereagujące.
Yury Tarabanko
@OP czy możesz stworzyć skrzypce demonstrujące problem?
Yury Tarabanko

Odpowiedzi:

259

To powinno działać. Odsyłając rekwizyt z powrotem, wysyłasz go jako obiekt, a raczej wysyłasz jako wartość lub alternatywnie używasz go jako obiektu w komponencie nadrzędnym. Po drugie, musisz sformatować obiekt json, aby zawierał pary wartości nazwa oraz użycie valueFieldi textFieldatrybutDropdownList

Krótka odpowiedź

Rodzic:

<div className="col-sm-9">
     <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
</div>

Dziecko:

handleLangChange = () => {
    var lang = this.dropdown.value;
    this.props.onSelectLanguage(lang);            
}

Szczegółowe:

EDYTOWAĆ:

Biorąc pod uwagę, że React.createClass jest przestarzałe od wersji 16.0, lepiej jest iść dalej i stworzyć React Component poprzez rozszerzenie React.Component. Będzie wyglądało przekazywanie danych z elementu potomnego do elementu nadrzędnego za pomocą tej składni

Rodzic

class ParentComponent extends React.Component {

    state = { language: '' }

    handleLanguage = (langValue) => {
        this.setState({language: langValue});
    }

    render() {
         return (
                <div className="col-sm-9">
                    <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
                </div>
        )
     }
}

Dziecko

var json = require("json!../languages.json");
var jsonArray = json.languages;

export class SelectLanguage extends React.Component {
    state = {
            selectedCode: '',
            selectedLanguage: jsonArray[0],
        }

    handleLangChange = () => {
        var lang = this.dropdown.value;
        this.props.onSelectLanguage(lang);            
    }

    render() {
        return (
            <div>
                <DropdownList ref={(ref) => this.dropdown = ref}
                    data={jsonArray} 
                    valueField='lang' textField='lang'
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
}

Przy użyciu createClassskładni, której OP użył w swojej odpowiedzi Parent

const ParentComponent = React.createClass({
    getInitialState() {
        return {
            language: '',
        };
    },

    handleLanguage: function(langValue) {
        this.setState({language: langValue});
    },

    render() {
         return (
                <div className="col-sm-9">
                    <SelectLanguage onSelectLanguage={this.handleLanguage} /> 
                </div>
        );
});

Dziecko

var json = require("json!../languages.json");
var jsonArray = json.languages;

export const SelectLanguage = React.createClass({
    getInitialState: function() {
        return {
            selectedCode: '',
            selectedLanguage: jsonArray[0],
        };
    },

    handleLangChange: function () {
        var lang = this.refs.dropdown.value;
        this.props.onSelectLanguage(lang);            
    },

    render() {

        return (
            <div>
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    valueField='lang' textField='lang'
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
});

JSON:

{ 
"languages":[ 

    { 
    "code": "aaa", 
    "lang": "english" 
    }, 
    { 
    "code": "aab", 
    "lang": "Swedish" 
    }, 
  ] 
}
Shubham Khatri
źródło
Dzięki Shubham, twoja odpowiedź rozwiązała problem, ale nie pokazuje wybranego elementu na liście rozwijanej. Po tym jest pusty: /
Birish
@Sarah Podczas tworzenia dropDownList przypisałeś jego wartość to this.state.selectedLanguage i nie jest on inicjowany żadną wartością. To może być problem. Którego składnika DropdownList używasz. Jeśli wiem, może uda mi się rozwiązać ten problem.
Shubham Khatri
Masz rację. this.state.selectedLanguageWydaje się być zawsze zerowy: / Używam od DropdownListreact-widgets
Birish
@ Sarah Wprowadziłem niewielką zmianę w kodzie, w tym powiązanie wartości z funkcją onChange i ustawienie wartości stanu początkowego. Spróbuj tego i powiedz mi, czy to działa dla Ciebie
Shubham Khatri
Zwraca błąd: Uncaught ReferenceError: value is not defined. onChange={this.handleLangChange.bind(this, this.value)}
Dokonałem
108

Aby przekazać dane z komponentu podrzędnego do komponentu nadrzędnego

W komponencie nadrzędnym:

getData(val){
    // do not forget to bind getData in constructor
    console.log(val);
}
render(){
 return(<Child sendData={this.getData}/>);
}

W komponencie podrzędnym:

demoMethod(){
   this.props.sendData(value);
 }
Manisha Tan
źródło
15
Nie zapomnij this.getData = this.getData.bind(this);w konstruktorze, ponieważ możesz dostać to. SetState nie jest funkcją, jeśli chcesz manipulować stanem w getData.
Miro J.,
12

Znalazłem podejście, jak uzyskać dane od komponentu podrzędnego od rodziców, kiedy są potrzebne.

Rodzic:

class ParentComponent extends Component{
  onSubmit(data) {
    let mapPoint = this.getMapPoint();
  }

  render(){
    return (
      <form onSubmit={this.onSubmit.bind(this)}>
        <ChildComponent getCurrentPoint={getMapPoint => {this.getMapPoint = getMapPoint}} />
        <input type="submit" value="Submit" />
      </form>
    )
  }
}

Dziecko:

class ChildComponent extends Component{
  constructor(props){
    super(props);

    if (props.getCurrentPoint){
      props.getCurrentPoint(this.getMapPoint.bind(this));
    }
  }

  getMapPoint(){
    return this.Point;
  }
}

Ten przykład pokazuje, jak przekazać funkcję z komponentu podrzędnego do nadrzędnego i użyć tej funkcji, aby uzyskać dane od potomka.

MrDuDuDu
źródło
10

Rozważanie składników funkcji React i używanie haków stają się coraz bardziej popularne, dam prosty przykład przekazywania danych z elementu potomnego na element nadrzędny

w komponencie funkcji rodzica będziemy mieli:

import React, { useState, useEffect } from "react";

następnie

const [childData, setChildData] = useState("");

i przekazanie setChildData (które wykonują zadanie podobne do this.setState w Class Components) do Child

return( <ChildComponent passChildData={setChildData} /> )

w Child Component najpierw otrzymujemy rekwizyty

function ChildComponent(props){ return (...) }

następnie możesz przekazać dane tak jak za pomocą funkcji obsługi

const functionHandler = (data) => {

props.passChildData(data);

}
Shayan Moghadam
źródło
3

Metoda React.createClass została uznana za przestarzałą w nowej wersji React, możesz to zrobić bardzo prosto w następujący sposób, aby jeden komponent funkcjonalny i inny komponent klasy utrzymywał stan:

Rodzic:

const ParentComp = () => {
  
  getLanguage = (language) => {
    console.log('Language in Parent Component: ', language);
  }
  
  <ChildComp onGetLanguage={getLanguage}
};

Dziecko:

class ChildComp extends React.Component {
    state = {
      selectedLanguage: ''
    }
    
    handleLangChange = e => {
        const language = e.target.value;
        thi.setState({
          selectedLanguage = language;
        });
        this.props.onGetLanguage({language}); 
    }

    render() {
        const json = require("json!../languages.json");
        const jsonArray = json.languages;
        const selectedLanguage = this.state;
        return (
            <div >
                <DropdownList ref='dropdown'
                    data={jsonArray} 
                    value={tselectedLanguage}
                    caseSensitive={false} 
                    minLength={3}
                    filter='contains'
                    onChange={this.handleLangChange} />
            </div>            
        );
    }
};

Sania Khushbakht Jamil
źródło
3
Tylko uwaga ... powinieneś odnieść się do konkretnej wersji React zamiast „nowej wersji”, aby w przyszłości potwierdzić tę odpowiedź.
steve-o
3

od elementu potomnego do elementu macierzystego, jak poniżej

komponent nadrzędny

class Parent extends React.Component {
   state = { message: "parent message" }
   callbackFunction = (childData) => {
       this.setState({message: childData})
   },
   render() {
        return (
            <div>
                 <Child parentCallback = {this.callbackFunction}/>
                 <p> {this.state.message} </p>
            </div>
        );
   }
}

składnik potomny

class Child extends React.Component{
    sendBackData = () => {
         this.props.parentCallback("child message");
    },
    render() { 
       <button onClick={sendBackData}>click me to send back</button>
    }
};

Mam nadzieję, że ta praca

Manoj Rana
źródło
2

w React v16.8+komponencie funkcji można użyć useState()do utworzenia stanu funkcji, który pozwala zaktualizować stan nadrzędny, a następnie przekazać go dziecku jako atrybutowi rekwizytów, a następnie w komponencie podrzędnym można uruchomić funkcję stanu nadrzędnego, poniżej znajduje się działający fragment kodu :

const { useState , useEffect } = React;

function Timer({ setParentCounter }) {
  const [counter, setCounter] = React.useState(0);

  useEffect(() => {
    let countersystem;
    countersystem = setTimeout(() => setCounter(counter + 1), 1000);

    return () => {
      clearTimeout(countersystem);
    };
  }, [counter]);

  return (
    <div className="App">
      <button
        onClick={() => {
          setParentCounter(counter);
        }}
      >
        Set parent counter value
      </button>
      <hr />
      <div>Child Counter: {counter}</div>
    </div>
  );
}

function App() {
  const [parentCounter, setParentCounter] = useState(0);

  return (
    <div className="App">
      Parent Counter: {parentCounter}
      <hr />
      <Timer setParentCounter={setParentCounter} />
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>

KORZEŃ
źródło
1

Możesz nawet ominąć funkcję nadrzędną, aktualizując bezpośrednio stan

W komponencie nadrzędnym:

render(){
 return(<Child sendData={ v => this.setState({item: v}) } />);
}

W elemencie potomnym:

demoMethod(){
   this.props.sendData(value);
}
Banzy
źródło
0

Chodzi o to, aby wysłać do dziecka wywołanie zwrotne, które zostanie wywołane w celu zwrócenia danych

Kompletny i minimalny przykład użycia funkcji:

Aplikacja utworzy dziecko, które obliczy losową liczbę i odeśle ją bezpośrednio do rodzica, co da console.logwynik

const Child = ({ handleRandom }) => {
  handleRandom(Math.random())

  return <span>child</span>
}
const App = () => <Child handleRandom={(num) => console.log(num)}/>
Fabien Sa
źródło
0

Składnik nadrzędny: -TimeModal

  handleTimeValue = (timeValue) => {
      this.setState({pouringDiff: timeValue});
  }

  <TimeSelection 
        prePourPreHours={prePourPreHours}
        setPourTime={this.setPourTime}
        isPrePour={isPrePour}
        isResident={isResident}
        isMilitaryFormatTime={isMilitaryFormatTime}
        communityDateTime={moment(communityDT).format("MM/DD/YYYY hh:mm A")}
        onSelectPouringTimeDiff={this.handleTimeValue}
     />

Uwaga : - onSelectPouringTimeDiff = {this.handleTimeValue}

W podrzędnym komponencie wywołania rekwizyty, gdy są wymagane

 componentDidMount():void{
      // Todo use this as per your scenrio
       this.props.onSelectPouringTimeDiff(pouringDiff);  
  }
Keshav Gera
źródło