简体   繁体   中英

How to get state from child to parent react

I'm new in React

I have two components. Parent Square , child Row .

I want to get setValues cellTop and cellLeft from Row to parent and use it.

How can I do it.

My code is bellow

 var Square = React.createClass({ getInitialState: function () { return { countRow: 4, countCol: 4, mouseOnTable: false, onDelRow: false, onDelCol: false } }, appendCol: function() { var countColNew = this.state.countCol + 1; this.setState({countCol: countColNew}); //change initiale state "countCol" (add new column) //console.log(this.state.countCol) }, appendRow: function() { var countRowNew = this.state.countRow + 1; this.setState({countRow: countRowNew}); //change initiale state "countRow" (add new row) //console.log(this.state.countRow) }, deleteCol: function() { var countColNew = this.state.countCol - 1; this.setState({countCol: countColNew}); //change initiale state "countCol" (delete col) //console.log(this.state.countCol) }, deleteRow: function() { var countRowNew = this.state.countRow - 1; this.setState({countRow: countRowNew}); //change initiale state (delete row) //console.log(this.state.countRow) }, hiddenButtons: function(){ var mouseOnTableNew = true; this.setState({mouseOnTable: mouseOnTableNew}) }, showButtons: function(){ var mouseOnTableNew = false; this.setState({mouseOnTable: mouseOnTableNew}) }, render: function() { var timeOut; return ( <div className='square'> <table className='square__table' onMouseOver={this.hiddenButtons} onMouseLeave={() => {timeOut=setTimeout(this.showButtons,200)}}> <Row countRow={this.state.countRow} countCol={this.state.countCol} ref={(ref) => this.state} /> </table> <button className="square__button square__button_append square__button_col-append" onClick={this.appendCol}> </button> <button className="square__button square__button_delete square__button_col-delete" style={this.state.countCol===1 || this.state.mouseOnTable===false || this.state.onDelRow===true ? {visibility: "hidden"} : {visibility: "visible"}} onClick={this.deleteCol} onMouseOver={() => {clearTimeout(timeOut); this.setState({onDelCol:true})}} onMouseLeave={() => {this.setState({onDelCol:false})}}> </button> <button className="square__button square__button_append square__button_row-append" onClick={this.appendRow}> </button> <button className="square__button square__button_delete square__button_row-delete" style={this.state.countRow===1 || this.state.mouseOnTable===false || this.state.onDelCol===true ? {visibility: "hidden"} : {visibility: "visible"}} onClick={this.deleteRow} onMouseOver={() => {clearTimeout(timeOut); this.setState({onDelRow:true})}} onMouseLeave={() => {this.setState({onDelRow:false})}}> </button> </div> ) } }) //================================================== var Row = React.createClass({ getInitialState: function(){ return { cellTop: 0, cellLeft: 0, } }, createCol: function() { var columns = []; for(let i = 0; i < this.props.countCol; i++){ columns.push(this.createCell) } return columns; }, createRow: function (k) { return ( <tr key={k}> {this.createCol().map(function(cell,key){ return ( cell(key) ) })} </tr> ) }, createCell: function(k){ return ( <td key={k}> <div className="square__cell" onMouseOver={this.getMousePosition}></div> </td> ) }, getMousePosition: function(element){ let coordinates = element.target.getBoundingClientRect(); let top = coordinates.top; let left = coordinates.left; this.setState({ cellTop: top, cellLeft: left }) }, render: function(){ var lines = [] for (let i = 0; i < this.props.countRow; i++) { lines.push(this.createRow(i)) } return ( <tbody> {lines} </tbody> ) } }) 

I would recommend you to not use state in components at all. This just leads to problems when you want to control parent component from child.

Instead,

  • make all components to receive data via props
  • move state and all data into external object (store)
  • make the store update your components when the data changes
  • from components just update store

Look at https://github.com/reflux/refluxjs

+---------+       +--------+       +-----------------+
¦ Actions ¦------>¦ Stores ¦------>¦ View Components ¦
+---------+       +--------+       +-----------------+
     ^                                      ¦
     +--------------------------------------+

You can pass your child component a callback function that accepts two arguments, cellTop and cellLeft . In your child component pass cellTop and cellLeft values at the same time you are calling getMousePosition() function in your child component.

In your parent component create a function like this:

handleSizeChange: function(cellTop, cellLeft){
    this.setState({
        cellTop: cellTop,
        cellLeft: cellLeft
    })
},

In your Parent <Row> component pass a callback function as a prop like this:

<Row countRow={this.state.countRow}
     countCol={this.state.countCol}
     ref={(ref) => this.state}
     onSizeChange={this.handleSizeChange}
/>

In your Child component add this.props.handleSizeChange(top, left) to your getMousePostion() function:

getMousePosition: function(element){

    let coordinates = element.target.getBoundingClientRect();
    let top = coordinates.top;
    let left = coordinates.left;

    this.setState({
        cellTop: top,
        cellLeft: left
    })

    this.props.handleSizeChange(top, left)
},

Its also true that whenever possible its best for data to flow from Parent -> Child components, but callback functions are common for things like button events. You could use something like Redux to handle state management, but that is fairly advanced and is probably overkill if this is a simple beginner application.

Also, you should be using the newest React syntax for components. Create new classes like this:

import React, { Component } from 'react'

class App extends Component {
      constructor() {
          super()

          //getinitialstate
          this.state = {
            cellTop: 0,
            cellLeft: 0
          }
      }
}

and define class methods like this:

  componentWillMount() {
    // this runs right before the <App> is rendered

  })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM