Làm cách nào để truyền dữ liệu từ thành phần con sang cha mẹ của nó trong ReactJS?


210

Tôi đang cố gắng gửi dữ liệu từ một thành phần con đến cha mẹ của nó như sau:

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

và đây là thành phần con:

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

Những gì tôi cần là để có được giá trị được lựa chọn bởi người dùng trong thành phần cha. Tôi đang gặp lỗi này:

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

Bất cứ ai có thể giúp tôi tìm ra vấn đề?

PS Thành phần con đang tạo danh sách thả xuống từ tệp json và tôi cần danh sách thả xuống để hiển thị cả hai thành phần của mảng json cạnh nhau (như: "aaa, tiếng Anh" là lựa chọn đầu tiên!)

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

3
<SelectLanguage onSelectLanguage={this.handleLanguage*Code*}/> một lỗi đánh máy.
Yury Tarabanko

@YuryTarabanko Cảm ơn, nhưng vẫn nhận được cùng một lỗi
Birish

@DavinTryon Tôi nên thêm nó như thế nào? Tôi đã thử như thế này: handleLanguageCode: function(langValue) { this.setState({ language: langValue }).bind(this); },Nhưng nó trả về một lỗi:ncaught TypeError: Cannot read property 'bind' of undefined
Birish

2
@DavinTryon createClassautobinds phương pháp không phản ứng.
Yury Tarabanko

@OP bạn có thể tạo ra một fiddle chứng minh vấn đề?
Yury Tarabanko

Câu trả lời:


258

Điều này nên làm việc. Trong khi gửi lại prop, bạn đang gửi nó dưới dạng một đối tượng chứ không gửi nó như một giá trị hoặc sử dụng nó như một đối tượng trong thành phần cha. Thứ hai, bạn cần định dạng đối tượng json của mình để chứa các cặp giá trị tên và sử dụng valueFieldtextFieldthuộc tính củaDropdownList

Câu trả lời ngắn

Cha mẹ:

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

Đứa trẻ:

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

Chi tiết:

BIÊN TẬP:

Xem xét React.createClass không được chấp nhận từ v16.0 trở đi, tốt hơn là tiếp tục và tạo Thành phần React bằng cách mở rộng React.Component. Truyền dữ liệu từ con sang thành phần cha mẹ với cú pháp này sẽ giống như

Cha mẹ

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

Đứa trẻ

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

Sử dụng createClasscú pháp mà OP đã sử dụng trong câu trả lời của mình 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>
        );
});

Đứa trẻ

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" 
    }, 
  ] 
}

Cảm ơn Shubham, câu trả lời của bạn đã khắc phục vấn đề, nhưng nó không hiển thị mục được chọn trong danh sách thả xuống. Đó là sản phẩm nào sau đó: /
Birish

@Sarah Trong khi tạo dropDownList, bạn đã gán giá trị của nó là this.state.selectedL Language và điều đó không được khởi tạo cho bất kỳ giá trị nào. Đó có thể là vấn đề. Thành phần DropdownList nào bạn đang sử dụng. Nếu tôi biết có lẽ tôi có thể làm việc để giải quyết vấn đề.
Shubham Khatri

Bạn đúng rồi. Các this.state.selectedLanguagedường như luôn luôn là null: / Tôi đang sử dụng DropDownList từreact-widgets
Birish

@Sarah Tôi đã thực hiện một thay đổi nhỏ đối với mã, bao gồm cả ràng buộc giá trị với hàm onChange và đặt giá trị trạng thái ban đầu. Hãy thử điều này và cho tôi biết nếu nó hoạt động cho bạn
Shubham Khatri

Trả về lỗi : Uncaught ReferenceError: value is not defined. Tôi đã thực hiện thay đổi này: onChange={this.handleLangChange.bind(this, this.value)}và không có lỗi nào trả về, nhưng nó vẫn không hiển thị giá trị được chọn :(
Birish

108

Để truyền dữ liệu từ thành phần con sang thành phần cha

Trong thành phần phụ huynh:

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

Trong thành phần con:

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

15
Đừng quên this.getData = this.getData.bind(this);trong hàm tạo, vì bạn có thể nhận được điều này.setState không phải là một hàm nếu bạn muốn thao tác trạng thái trong getData.
Miro J.

12

Tôi tìm thấy cách tiếp cận làm thế nào để lấy dữ liệu từ thành phần con trong cha mẹ khi tôi cần.

Cha mẹ:

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

Đứa trẻ:

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

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

  getMapPoint(){
    return this.Point;
  }
}

Ví dụ này cho thấy cách truyền chức năng từ thành phần con sang cha mẹ và sử dụng chức năng này để lấy dữ liệu từ con.


10

Xem xét các thành phần chức năng React và sử dụng Hook đang trở nên phổ biến hơn những ngày này, tôi sẽ đưa ra một ví dụ đơn giản về cách truyền dữ liệu từ con sang thành phần cha

Trong Thành phần Chức năng Phụ huynh, chúng ta sẽ có:

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

sau đó

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

và chuyển setChildData (thực hiện một công việc tương tự this.setState trong các thành phần lớp) cho Child

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

Trong Thành phần trẻ em trước tiên chúng ta có được đạo cụ nhận

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

sau đó bạn có thể truyền dữ liệu bằng cách sử dụng hàm xử lý

const functionHandler = (data) => {

props.passChildData(data);

}

3

Phương thức React.createClass không được dùng nữa trong phiên bản mới của React, bạn có thể thực hiện nó rất đơn giản theo cách sau đây tạo một thành phần chức năng và thành phần lớp khác để duy trì trạng thái:

Cha mẹ:

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

Đứa trẻ:

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
Chỉ cần một lưu ý ... bạn nên tham khảo phiên bản cụ thể của React thay vì "phiên bản mới" để chứng minh câu trả lời này trong tương lai.
steve-o

3

từ thành phần con đến thành phần cha mẹ như dưới đây

thành phần cha mẹ

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

thành phần con

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

Tôi hy vọng công việc này


1

Bạn thậm chí có thể tránh chức năng tại cha mẹ cập nhật trạng thái trực tiếp

Trong thành phần phụ huynh:

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

Trong Thành phần con:

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

1

trong React v16.8+thành phần chức năng, bạn có thể sử dụng useState()để tạo trạng thái chức năng cho phép bạn cập nhật trạng thái cha, sau đó chuyển nó sang con làm thuộc tính đạo cụ, sau đó bên trong thành phần con bạn có thể kích hoạt chức năng trạng thái cha, sau đây là đoạn trích làm việc :

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>


0

Ý tưởng là gửi một cuộc gọi lại cho đứa trẻ sẽ được gọi để trả lại dữ liệu

Một ví dụ đầy đủ và tối thiểu sử dụng các hàm:

Ứng dụng sẽ tạo ra một đứa trẻ sẽ tính toán một số ngẫu nhiên và gửi lại trực tiếp cho phụ huynh, console.logkết quả sẽ cho kết quả

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

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

0

Thành phần phụ huynh: -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}
     />

Lưu ý : - onSelectPouringTimeDiff = {this.handleTimeValue}

Trong Đạo cụ gọi thành phần con khi có yêu cầu

 componentDidMount():void{
      // Todo use this as per your scenrio
       this.props.onSelectPouringTimeDiff(pouringDiff);  
  }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.