React - 从嵌套组件访问更新值

时间:2016-03-18 14:22:46

标签: reactjs reactjs-flux

我有一个包含行的表,可以编辑一行中的每个单元格。每行都有一个按钮,用于将该行中的所有单元格提交给数据库。我想知道的是,如果单元格中的数据已被更改,我是如何从提交事件实际发生的组件中访问新值的?

目前我正在构建表格:

主表:

import React from 'react';
import TableWithDataHeader from './TableWithDataHeader.jsx';
import Row from './Row.jsx';
import AppStore from '../../stores/AppStore';

export default class Table extends React.Component {

    handleSubmitEvent = (e) => {
        e.preventDefault();
        /////What do I do here to get the updated values???////
    };

    render() {
        return (
            <div>
                <div className="row">
                    <table className="table table-striped table-bordered">
                        <thead>
                            <TableWithDataHeader />
                        </thead>
                        <Row data={AppStore.getCells().historycells} handleSubmitEvent={this.handleSubmitEvent} />
                    </table>
                </div>
            </div>
        );
    }
}

行组件:

import React from 'react';
import TableBody from './TableBody.jsx';
import AppStore from '../../stores/AppStore';

export default class Row extends React.Component {
    state = {data: this.props.data};

    handleSubmitEvent = (e) => {
        this.props.handleSubmitEvent(e);
    };

    render() {

        let {data} = this.state;

        return (
            <tbody>
                <tr id={AppStore.getRowId()}>
                    {this.state.data.map(cell => {
                        return (
                            <TableBody key={cell.id} cell={cell.contents} />
                        );
                    })}
                    <td className="table-button">
                        <button type="submit" className="btn btn-primary" onClick={this.handleSubmitEvent.bind(this)}>Save Row</button>
                    </td>
                </tr>
            </tbody>
        );
    }
}

细胞成分:

import React from 'react';
import EditableCells from './EditableCells.jsx';

export default class TableBody extends React.Component {

    render() {
        return (
            <EditableCells data={this.props.cell} />
        );
    }
}

编辑单元组件:

import React from 'react';

export default class EditableCells extends React.Component {
    state = {isEditMode: false, data: ""};

    componentWillMount() {
        this.setState({
            isEditMode: this.props.isEditMode,
            data: this.props.data
        });
    }

    handleEditCell = (e) => {
        this.setState({isEditMode: true});
    };

    handleKeyDown = (e) => {
        switch (e.keyCode) {
            case 13: //Enter
            this.setState({isEditMode: false});
            break;
        }
    };

    handleChange = (e) => {
        this.setState({data: e.target.value});
    };

    render() {

        let {isEditMode, data} = this.state;

        let cellHtml;

        if (this.state.isEditMode) {
            cellHtml = <input type="text" className="form-control" value={this.state.data} onKeyDown={this.handleKeyDown} onChange={this.handleChange} />
        } else {
            cellHtml = <div onClick={this.handleEditCell}>{this.state.data}</div>
        }
        return (
            <td className="text-center">{cellHtml}</td>
        );
    }
}

任何有关我如何能够做到这一点的帮助都会非常有帮助,当然,非常感谢!

感谢您的时间

2 个答案:

答案 0 :(得分:2)

尝试将应用程序状态保持在组件树中最高级别。在这种情况下,简单的方法是让Table组件处理数据状态,并提供事件处理程序。将这些作为道具传递给Row,并根据需要进一步向下传递。概念证明:https://jsfiddle.net/dannyjolie/4jfxeag8/1/

一般的经验法则是永远不要使用组件状态,并将应用程序更改中的所有更改用于最顶级的组件,但输入字段有时是规则的例外,因为您可能不想修改应用程序打字的状态。

它的基础:

export default class Table extends React.Component {
  constructor(props) {
    super(props);
    this.state.cells = ['Foo', 'Bar']; // Fetch something from your store, or better, pass the cells as props from parent component
    this.handleSubmitEvent = this.handleSubmitEvent.bind(this);
    this.handleChangeEvent = this.handleChangeEvent.bind(this);
  }
  handleSubmitEvent () {
    // Up to date cells are stored in this.state
  }
  handleChangeEvent (value, cell) {
    // All values are available in this.state, do with that as you wish :)
  }
  render () {
    ....
    <Row handleSubmitEvent={this.handleSubmitEvent} 
         handleChangeEvent={this.handleChangeEvent}
         data={this.state.cells} />
    ....
  }
}

答案 1 :(得分:1)

React仅填充数据更改,并在必要时从上到下重新呈现DOM的已更改部分。你可以做的是通过props让子组件访问父组件的状态:

class ParentComponent extends Component {
  handleWhatever(updated) {
    this.setState({
      whatever: updated
    });
  }

  render() {
    return (
      <ChildComponent onEdit={::this.handleWhatever} />
    );
  }
}

class ChildComponent extends Component {
  render() {
    return (
      <SomethingEditable onChange={this.props.onEdit} />
    );
  }
}

所以,这个想法是:

  1. ParentComponent中,您定义了一种方法,该方法在调用时会更改此组件的状态,即ParentComponent
  2. ChildComponent中,您每次更改时都有能够调用函数的内容(最常见的示例:input元素及其onBlur事件)
  3. 每当您更改ChildComponent内的内容时,它都会调用从ParentComponent传递的函数,而ParentComponent依次从底部到顶部方向提供数据并将其传递给{{ 1}}。
  4. 调用该函数boundParentComponent,然后调用setState,这会更改ParentComponent的状态,并反映(或不反映) -reder整个子树(React负责仅挑选那些真正需要重新渲染的组件。)
  5. 这是解决移动数据的方法的经典方法,该方向与React期望它的流动方式相反。

    您可以根据需要设置尽可能多的嵌套图层,只是不要忘记将该功能传递到所有图层。