如何处理render()中更新的组件状态?

时间:2019-02-09 13:47:38

标签: reactjs

这是一个React组件,允许上传文本文件。文件内容稍后将显示在组件中。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getFile } from '../actions/fileActions';
import toJsonArray from '../utils/toJsonArray';

class TableInput extends Component {
  constructor() {
    super();

    this.state = {
      file: {},
      jsonArr: []
    };

    this.onFileUpload = this.onFileUpload.bind(this);
  }

  componentWillReceiveProps(nextProps) {    
    const { file } = nextProps.file;

    if (file) {
      this.setState({ file });
    }

    if (file) {
      let readFromFile;

      const reader = new FileReader();
      reader.onload = event => {
        readFromFile = event.target.result;
        this.setState({ jsonArr: toJsonArray(readFromFile) }, () => console.log('jsonArr:', this.state.jsonArr));
      };

      reader.onerror = error => console.log(error);
      reader.readAsText(file);
    }
  }

  componentDidUpdate(_, prevState) {
    if (this.state.jsonArr.length) {
      console.log('this.state.jsonArr:', this.state.jsonArr);
    }
  }

  onFileUpload() {
    const file = document.querySelector('input[type=file]').files[0];

    this.props.getFile(file);
  }

  render() {
    return (
      <div>
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Amount</th>
              <th>Description</th>
              <th>Date</th>
              <th>Billable</th>
              <th>Type</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>TableInput</td>
              <td>{this.state.file.name}</td>
              <td>{this.state.jsonArr['Memo'] ? 'it exists' : 'it does not'}</td>
            </tr>
          </tbody>
        </table>
        <label htmlFor='files' className='file-input-label'>
          Select File
        </label>
        <input type='file' id='files' className='file-input-hidden' onChange={this.onFileUpload} />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  file: state.file
});

export default connect(mapStateToProps, { getFile })(TableInput);

这里实际上不需要州的file属性。通过file操作将上载的this.props.getFile(file)发送到适当的reducer。 在jsonArr的{​​{1}}调用内,this.setState({ jsonArr: toJsonArray(readFromFile) })属性已正确填充了json对象数组。

如何在状态上新设置的componentWillReceiveProps(nextProps)属性显示在jsonArr内部?

到目前为止,我的render()空着。我想我可以使用<td>,但还没有弄清楚该怎么做。

componentDidUpdate()操作:

getFile()

相应的减速器

import { FILE_UPLOAD } from './types';

// dispatch uploaded file
export const getFile = (file) => (dispatch) => {    
  dispatch({
    type: FILE_UPLOAD,
    payload: file
  });
};

用于返回json数组的import { FILE_UPLOAD } from '../actions/types'; const initialState = { file: {} }; export default function(state = initialState, action) { switch(action.type) { case FILE_UPLOAD: return { ...state, file: action.payload }; default: return state; } }; util方法。该数组由具有toJsonArray()对的json对象组成。

key: value

1 个答案:

答案 0 :(得分:0)

解决方案是对this.setState()中上载的文本文件中的每个键应用componentWillReceiveProps(nextProps)。该代码需要清除以外的其他内容。

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getFile } from '../actions/fileActions';
import toJsonArray from '../utils/toJsonArray';

class TableInput extends Component {
  constructor() {
    super();

    this.state = {
      file: {},     // as stated in the origin question not needed
      jsonArr: [],  // not needed either
      'Incurred Date': [],
      'Memo': [],
      'Person Name': [],
      'Amount': [],
      'Billable': [],
      'Entry Date': [],
      'Comment': [],
      length: 0,
      fileName: ''
    };

    this.onFileUpload = this.onFileUpload.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    const { file } = nextProps.file;

    if (file) {
      this.setState({ file });
    }

    if (file) {
      let readFromFile;

      const reader = new FileReader();
      reader.onload = event => {
        readFromFile = event.target.result;

        const jsonArray = toJsonArray(readFromFile);

        // various keys inside quotes below come from the uploaded file
        this.setState({
          'Incurred Date': jsonArray.map(item => item['Incurred Date']),
          'Memo': jsonArray.map(item => item['Memo']),
          'Person Name': jsonArray.map(item => item['Person Name']),
          'Amount': jsonArray.map(item => item['Amount']),
          'Billable': jsonArray.map(item => item['Billable']),
          'Entry Date': jsonArray.map(item => item['Entry Date']),
          'Comment': jsonArray.map(item => item['Comment']),
          length: jsonArray.length,
          fileName: file.name
        });
      };

      reader.onerror = error => console.log(error);
      reader.readAsText(file);
    }
  }

  onFileUpload() {
    const file = document.querySelector('input[type=file]').files[0];

    this.props.getFile(file);
  }

  render() {
    let rows = [];

    if (this.state.length) {
      for (let i = 0; i < this.state.length; i++) {
        rows.push(
          <tr key={i}>
        <td>{this.state['Person Name'] && this.state['Person Name'][i]}</td>
        <td>{this.state['Amount'] && this.state['Amount'][i]}</td>
        {this.state['Memo'] && this.state['Memo'][i] && <td>{this.state['Memo'][i]}</td>}
        {this.state['Comment'] && this.state['Comment'][i] && <td>{this.state['Comment'][i]}</td>}
        {this.state['Incurred Date'] && this.state['Incurred Date'][i] && <td>{this.state['Incurred Date'][i]}</td>}
        {this.state['Entry Date'] && this.state['Entry Date'][i] && <td>{this.state['Entry Date'][i]}</td>}
        <td>{this.state['Billable'] && this.state['Billable'][i]}</td>
        <td>{this.state.fileName === 'expenses.csv' ? 'Expense' : 'Time'}</td>
      </tr>
        )
      }
    }

    return (
      <div>
        <table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Amount</th>
              <th>Description</th>
              <th>Date</th>
              <th>Billable</th>
              <th>Type</th>
            </tr>
          </thead>
          <tbody>
            {rows}
          </tbody>
        </table>
        <label htmlFor='files' className='file-input-label'>Select File</label>
        <input type='file' id='files' className='file-input-hidden' onChange={this.onFileUpload} />
      </div>
    );
  }
}

const mapStateToProps = state => ({
  file: state.file
});

export default connect(mapStateToProps, { getFile })(TableInput);