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

React - Accessing updated values from nested components

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

这是我目前构建 table 的方式:

主要Table:

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

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

感谢您的宝贵时间

尽量让您的应用程序状态处于组件树中的最高级别。在这种情况下,简单的方法是让 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} />
    ....
  }
}

React 仅注入数据更改,并在必要时从上到下重新渲染 DOM 更改的部分。你可以做的是通过道具让子组件访问父组件的状态:

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.
  4. 函数被调用,boundParentComponent,所以 setState 被调用,这改变了 ParentComponent 的状态,它反映(或不反映)重新渲染整个子树(React 只负责挑选那些真正需要重新渲染的组件)。

这是解决数据移动方向与 React 预期数据流动方向相反的问题的经典方法。

您可以根据需要拥有任意多的嵌套层,只是不要忘记将该函数传递给所有层。