Як передавати дані з дочірнього компонента до його батьківського в ReactJS?


211

Я намагаюся надсилати дані від дочірнього компонента до його батьківського, як слід:

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

і ось дочірній компонент:

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

Що мені потрібно - це отримати вибране значення за користувачем у батьківському компоненті. Я отримую цю помилку:

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

Хтось може допомогти мені знайти проблему?

PS Дочірній компонент створює спадне меню з файлу json, і мені потрібен список, що випадає, щоб показати обидва елементи масиву json поруч (наприклад: "aaa, англійська мова" як перший вибір!)

{  
   "languages":[  
      [  
         "aaa",
         "english"
      ],
      [  
         "aab",
         "swedish"
      ],
}

3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> друкарська помилка.
Юрій Тарабанко

@YuryTarabanko Дякую, але все ж отримую ту ж помилку
Birish

@DavinTryon Як слід додати його? Я спробував так: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },Але вона повертає помилку:ncaught TypeError: Cannot read property 'bind' of undefined
Birish

2
@DavinTryon createClassсамостійно реагує на методи, що не реагують.
Юрій Тарабанко

@OP Чи можете ви створити загадку, яка демонструє проблему?
Юрій Тарабанко

Відповіді:


259

Це має спрацювати. Під час повернення реквізиту ви надсилаєте це як об'єкт, а надсилаєте його як значення або альтернативно використовуєте його як об'єкт у батьківському компоненті. По-друге, вам потрібно відформатувати об’єкт json, щоб він містив пари значень імен та використання valueFieldта textFieldатрибутDropdownList

Коротка відповідь

Батько:

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

Дитина:

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

Детально:

Редагувати:

Зважаючи на те, що React.createClass застарілий від v16.0 і далі, краще йти вперед і створити компонент React шляхом розширення React.Component. Передача даних від дочірнього до батьківського компонента з цим синтаксисом виглядатиме так

Батьківський

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

Дитина

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

Використання createClassсинтаксису, який ОП використовував у своїй відповіді Батько

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

Дитина

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, ваша відповідь вирішила проблему, але вона не відображає вибраний елемент у спадному списку. Після цього це порожньо: /
Birish

@Sarah Під час створення dropDownList ви присвоїли його значення this.state.selectedLanguage, і це не ініціалізується під будь-яке значення. Це може бути питання. Який компонент DropdownList ви використовуєте. Якщо я знаю, можливо, я можу попрацювати над цим, щоб вирішити проблему.
Шубхам Хатрі

Ти правий. this.state.selectedLanguage, Здається, завжди нуль: / Я використовую DropDownList зreact-widgets
Birish

@Sarah Я вніс невелику зміну коду, включаючи прив'язку значення функції OnChange до встановлення початкового значення стану. Спробуйте це і скажіть, чи спрацьовує це для вас
Shubham Khatri

Повертає помилку: Uncaught ReferenceError: value is not defined. Я вніс цю зміну: onChange={this.handleLangChange.bind(this, this.value)}і помилка не повертається, але все-таки вона не відображає вибране значення :(
Birish

108

Для передачі даних від дочірнього компонента до батьківського компонента

У батьківській складовій:

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

У дочірніх компонентах:

demoMethod(){
   this.props.sendData(value);
 }

15
Не забувайте this.getData = this.getData.bind(this);в конструкторі, тому що ви можете отримати this.setState - це не функція, якщо ви хочете маніпулювати станом у getData.
Міро Дж.

12

Я знайшов підхід, як отримати дані від дочірнього компонента у батьків, коли мені це потрібно.

Батько:

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

Дитина:

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

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

  getMapPoint(){
    return this.Point;
  }
}

Цей приклад показує, як передавати функцію від дочірнього компонента до батьківського і використовувати цю функцію для отримання даних від дочірнього.


10

З огляду на компоненти React Function та використання гачків набувають все більшої популярності в наші дні, я наведу простий приклад того, як передавати дані від дочірнього до батьківського компонента

в компоненті батьківської функції у нас буде:

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

тоді

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

і передача setChildData (які виконують роботу, подібну до цієї.setState в компонентах класу) до дитини

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

у Child Component спочатку ми отримуємо реквізит, що приймає

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

тоді ви можете передавати дані будь-яким чином, використовуючи функцію обробника

const functionHandler = (data) => {

props.passChildData(data);

}

3

Метод React.createClass був застарілим у новій версії React, ви можете це зробити дуже просто таким чином, щоб зробити один функціональний компонент та інший компонент класу для підтримки стану:

Батько:

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

Дитина:

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


3
Лише зауваження ... вам слід посилатися на конкретну версію React, а не на "нову версію", щоб надалі підтвердити цю відповідь.
steve-o

3

від дочірнього компонента до батьківського компонента, як показано нижче

батьківський компонент

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

дочірній компонент

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

Я сподіваюся, що ця робота


2

в React v16.8+компоненті функції ви можете використовувати useState()для створення стану функції, яка дозволяє оновлювати батьківський стан, потім передавати його дитині як атрибут реквізиту, тоді всередині дочірнього компонента ви можете запустити функцію батьківського стану, наступний робочий фрагмент :

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>


1

Ви навіть можете уникнути функції батьківського оновлення стану безпосередньо

У батьківській складовій:

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

У дочірньому компоненті:

demoMethod(){
   this.props.sendData(value);
}

0

Ідея полягає в тому, щоб надіслати зворотній дзвінок дитині, яку зателефонують, щоб повернути дані

Повний і мінімальний приклад з використанням функцій:

Додаток створить дочірню, яка обчислить випадкове число і відправить його назад безпосередньо батьків, що призведе console.logдо результату

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

  return <span>child</span>
}
const App = () => <Child handleRandom={(num) => console.log(num)}/>

0

Батьківський компонент: -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}
     />

Примітка : - onSelectPouringTimeDiff = {this.handleTimeValue}

У дочірньому реквізиті дзвінка підключення за потреби

 componentDidMount():void{
      // Todo use this as per your scenrio
       this.props.onSelectPouringTimeDiff(pouringDiff);  
  }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.