【问题标题】:React - require some aid with saving data to a tableReact - 需要一些帮助来将数据保存到表中
【发布时间】:2016-06-16 16:21:51
【问题描述】:

我有一个动态生成的列标题和行的表,用户可以在行中输入数据,当他们单击保存时,数据应该保存到该行中,但目前它没有将值保存到表,但它将它们保存在我的数据库中。理想情况下,我希望这样当单击保存按钮时,数据将保存到该行中,然后可以在该行中查看(如果这有意义的话)。

这是我正在使用的代码(我知道现在一团糟!):

数据输入表单代码:

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

export default class RowForm extends React.Component {
    state = {dataEntries: []};

    onChange = (event, element) => {
        let dataEntries = this.state.dataEntries;
        dataEntries[element] = event.target.value;
        this.setState({dataEntries});
    };

    editStop = () => {
        this.props.editStop();
    };

    handleSubmit = (e) => {
        e.preventDefault();

        let access_token = AppStore.getToken();
        let id = AppStore.getTable().id;
        let dataEntries = this.state.dataEntries;
        let dataEntriesArray = [];
        for (let key in dataEntries) {
            if (dataEntries.hasOwnProperty(key)) {
                dataEntriesArray.push({contents: dataEntries[key]});
            }
        }

        this.props.handleSubmit(access_token, id, dataEntriesArray);

    };

    componentDidMount() {
        let nameArray = AppStore.getTable().columns.map((obj) => {
            return obj.name;
        });

        let dataEntries = nameArray.reduce((obj, name) => {
            obj[name] = null;
            return obj;
        }, {});
        this.setState({dataEntries});
    }

    render() {

        let {dataEntries} = this.state;

        return (
            <tr>
                {Object.keys(dataEntries).map((element) => {
                    return (
                        <td key={element}><input type="text" className="form-control" id={element} placeholder="enter data" value={dataEntries[element]} onChange={event => this.onChange(event, element)} /></td>
                    );
                })}
                <td>
                    <button className="btn btn-default" onClick={this.editStop}><i className="fa fa-ban"></i>Cancel</button>
                    <button className="btn btn-success" onClick={this.handleSubmit}><i className="fa fa-check"></i>Save</button>
                </td>
            </tr>
        );
    }

输入并提交数据后(它是一个对象数组,如 dataEntriesArray = [{contents: "value"}, {contents: "value"}, {contents: "value"}, {contents: "值"}]。

这是我渲染表格的方式(我认为这是问题所在):

import React from 'react';
import TableHeader from './TableHeader.jsx';
import RowForm from './RowForm.jsx';
import {createRow} from '../../actions/DALIActions';
import AppStore from '../../stores/AppStore';

export default class Table extends React.Component {
    state = {rows: [], isNew: false, isEditing: false};

    handleAddRowClickEvent = () => {
        let rows = this.state.rows;
        rows.push({isNew: true});
        this.setState({rows: rows, isEditing: false});
    };

    handleEdit = (row) => {
        this.setState({isEditing: true});
    };

    editStop = () => {
        this.setState({isEditing: false});
    };

    handleSubmit = (access_token, id, dataEntriesArray) => {
        createRow(access_token, id, dataEntriesArray);
    };

    render() {

        let {rows, isNew, isEditing} = this.state;

        let headerArray = AppStore.getTable().columns;

        return (
            <div>
                <div className="row" id="table-row">
                    <table className="table table-striped">
                        <thead>
                            <TableHeader />
                        </thead>
                        <tbody>
                            {rows.map((row, index) => this.state.isEditing ?
                                <RowForm formKey={index} key={index} editStop={this.editStop} handleSubmit={this.handleSubmit} /> :
                                <tr key={index}>
                                    {headerArray.map((element, index) => {
                                        return (
                                            <td key={index} id={element.id}></td>
                                        );
                                    })}
                                    <td>
                                        <button className="btn btn-primary" onClick={this.handleEdit.bind(this, row)}><i className="fa fa-pencil"></i>Edit</button>
                                    </td>
                                </tr>)}
                        </tbody>
                    </table>
                </div>
                <div className="row">
                    <div className="col-xs-12 de-button">
                        <button type="button" className="btn btn-success" onClick={this.handleAddRowClickEvent}>Add Row</button>
                    </div>
                </div>
            </div>
        );
    }
}

我目前正在使用flux,理想情况下希望暂时继续使用它(我知道redux,但理想情况下我希望在开始重构我的代码之前让它在flux中工作)。我怀疑这是我渲染表格的方式的问题。

任何帮助将不胜感激,尤其是示例!

感谢您的宝贵时间!

【问题讨论】:

  • 当你点击保存时看起来好像没有更新状态,它调用了一个动作但实际上并没有更新状态,所以没有任何变化,因此没有任何东西被重新渲染。除非您自上而下渲染,否则您似乎也不会为任何商店事件添加任何侦听器来触发重新渲染。我想这不是您的 UI 不更新的原因。如果这是在正确的轨道上,我会重写作为答案。
  • 是的,我在想它是这样的,但是因为我通过映射数组来创建每一行中的单元格,所以对于如何告诉表格以正确的值进行更新有点难过在每个单元格中。有什么想法吗?
  • 父级应包含所有表数据,然后将其传递给子级。当数据更改时,它应该更改顶级数据结构,强制刷新并将该数据再次传播给孩子。在这种情况下,我假设表数据已经被提取并在存储中?您还可以通过保存每个变更来消除对保存按钮的需求,以保持服务器和 UI 状态同步。
  • 是的,但它只在表单提交后存储(表初始化时没有行也没有数据)。我正在努力的部分是如何将数据放入正确的单元格中,因为它们嵌套在各种地图函数中并且没有标识符,因为首先它们是没有价值的空单元格。关于我将如何做到这一点的任何想法?我需要保存按钮,因为一旦创建了一行,就可以对其进行编辑然后再次保存(这将更新数据的状态)。
  • 您不需要保存按钮(尽管您可能需要它),因为您所做的每个突变(更改单元格、添加行等)都会更改基础表数据,然后表数据更改可以(并且可能应该是,取决于您的用例)传播到服务器。在任何情况下,您都希望您的 UI 询问 更新商店中的状态,然后商店会通过表结构发出更改事件,父组件侦听该更改事件并使用来自店铺。我会把这个写下来作为答案,我们可能可以删除这个聊天。

标签: reactjs reactjs-flux


【解决方案1】:

看起来您可能希望将表数据提取到您的商店中,您的 UI 子元素触发更改事件,然后您的商店更新其数据并触发您的父组件可以侦听和更新的更改事件。

类似于以下简化示例,它会改变数组元素:

class Store extends EventEmitter {
  constructor() {
    super()

    this.data = [ 'a', 'b', 'c' ]
  }

  onChange() {
    this.emit( 'update', this.data )
  }

  mutate( index, value ) {
    this.data[ index ] = value
    this.onChange()
  }
}

var store = new Store()

class ChildComponent extends React.Component {
  constructor( props ) {
    super( props )
  }

  // You probably want to use a dispatcher rather than directly accessing the store
  onClick = event => {
    store.mutate( this.props.index, this.props.value + 'Z' )
  }

  render() {
    return <button onClick={ this.onClick }>{ this.props.value }</button>
  }
}

class ParentComponent extends React.Component {
  constructor( props ) {
    super( props )

    // You probably want to be smarter about initially populating state
    this.state = {
      data: store.data
    }
  }

  componentWillMount() {
    store.on( 'update', data => this.setState({ data: data }) )
  }

  render() {
    let cells = this.state.data.map( ( value, index ) => <ChildComponent index={ index } value={ value } /> )

    return (
      <div>
        { cells }
      </div>
    )
  }
}

为了简洁,这里的子组件直接告诉商店更改值,您可能希望发送消息/操作并让商店决定如何响应,关键是将商店数据传递给父组件,这会更新其状态并触发重新渲染。

这里的流程本质上是 UI 是愚蠢的,它只是渲染从商店收集的数据,并发送一条消息告诉商店在检测到用户操作时更新/改变(在这种情况下是按下按钮但听起来您需要某种类型的输入),当存储中的数据发生更改时,它会发出(或者也可以使用调度程序)一个更改事件,该事件会强制 UI 重新呈现新状态。在此阶段重新渲染子组件时,它们会填充新的数据状态,以确保您的 UI 保持一致。

【讨论】:

  • 感谢您的帮助!
猜你喜欢
  • 2011-12-12
  • 2012-03-02
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 2017-03-09
  • 2011-01-13
  • 1970-01-01
相关资源
最近更新 更多