当使用FileReader API选择上传文件时,我正在尝试在React / Redux应用程序中显示一些文件内容 . 我能够显示内容,但在FileReader的onload事件处理程序中调用setState会导致无限渲染 .
import _ from 'lodash';
import React, { Component } from 'react';
import { reduxForm, Field, formValueSelector } from 'redux-form';
import Button from 'material-ui/Button';
import * as actions from '../../actions';
import { connect } from 'react-redux';
import {
Select,
TextField,
} from 'redux-form-material-ui';
import { renderFileInput } from '../helpers/form_helpers';
class ImportLeads extends Component {
state = {
fields: []
}
handleFormSubmit({ leadsCSV }) {
const { listid } = this.props;
this.props.importLeads(leadsCSV, listid);
}
renderMapping() {
const { CSVFile } = this.props;
console.log(CSVFile);
const temp = [];
if(CSVFile) {
const r = new FileReader();
r.readAsText(CSVFile, "UTF-8");
r.onload = (e) => {
const content = e.target.result;
const firstLine = content.split('\n', 1)[0];
const fieldsArray = firstLine.split(',');
console.log(fieldsArray);
_.map(fieldsArray, field => {
console.log(field);
temp.push(<div>{field}</div>);
});
this.setState({ fields: temp });
}
r.onerror = function(e) {
console.log("Error reading file");
}
}
return (
<div>
{this.state.fields}
</div>
);
}
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<div>
<Field
name="leadsCSV"
component={renderFileInput}
type="file"
text="Import CSV"
/>
<div style={{ marginTop: '10px' }}>
<Button type="submit" variant="raised">Upload</Button>
</div>
</div>
</form>
{this.renderMapping()}
</div>
);
}
}
ImportLeads = reduxForm({
form: 'importLeads',
})(ImportLeads);
const selector = formValueSelector('importLeads');
ImportLeads = connect(
state => {
const CSVFile = selector(state, 'leadsCSV');
return {
CSVFile
}
}
)(ImportLeads);
export default ImportLeads;
我使用redux表单来处理文件输入并通过使用connect将其作为props提供来获取文件的值 .
我读到在render方法中调用setState时通常会发生无限渲染 . 有没有更好的方法来解决这个问题,而不是让它无限渲染?谢谢 .
3 回答
React具有特殊的“生命周期”方法,对于这个用例非常有用 .
如果定义
componentWillMount()
方法,则会在第一次渲染之前调用它 . 如果你有额外的资源,你需要加载你可以踢那里 .因为看起来你想重新运行那些计算,如果道具改变你也会想要使用
componentWillReceiveProps(nextProps)
来重新运行你的计算基于新的道具 . 请注意this.props
尚未反映新道具,您需要从参数中获取这些道具 .最后,尽管你的情况不必要,你应该用
componentWillUnmount()
来熟化自己,这将允许你自己清理(例如删除事件监听器,取消计时器等),如果你不这样做,你很容易导致内存泄漏,甚至更糟 .您可以在文档中熟悉更多生命周期方法:https://reactjs.org/docs/react-component.html#the-component-lifecycle
最后一个示例演示了如何使用这些方法来解决类似“解析”换行符分隔列表的问题 .
在
renderMapping()
内部,调用setState
导致重新渲染组件 .在组件
render
中,您有{this.renderMapping()}
导致再次调用renderMapping
.这个过程重复n次导致无限渲染 .
如果
fieldsArray
已包含field
,则应检入renderMapping
. 如果是这样,则不应将其推送到阵列 . (因为你将另一个div中的相同字段推入到数组中,它会不断地重新渲染)