我正在尝试解析从firebase接收的数据并将此新数据传递给组件。数据与promises异步获取。我遇到的问题是它没有第一次呈现,即使我已经设置componentDidMount
并调用函数来解析那里的数据。
我从firebase收到的数据如下:
faults: [{
name: "Foo",
status: "Open"
type: "type1"
},
{
name: "Bar",
status: "Open"
type: "type2"
}],
types: [{
key: "type1",
type: "Accident"
},
{
key: "type2",
type: "Crash"
}]
如您所见,我需要解析数据以使用type
中的正确名称替换types
个错误。
为此,我有一个解析数据并设置状态的函数。这是代码:
parseFields() {
let parsedFields = [];
this.props.fields.forEach((field) => {
const typeSelected= this.props.estados.find(element => element.key === field.type) || '';
let parsedField = Object.assign({}, field);
parsedField['type'] = typeSelected.type;
parsedFields.push(parsedField);
});
this.setState({data: parsedFields});
}
此功能在componentDidMount
和componentWillReceiveProps
上调用,但是当组件安装时,不会显示任何数据。但是,当组件收到新的道具时,它会正确显示。
我做错了吗?我也尝试在componentWillMount
上调用此函数,但它不适用于第一个渲染。
根据要求,这是组件代码:
import React from 'react'
import Table from './Table';
class FaultList extends React.Component {
constructor(props) {
super(props);
this.columns = [
{
name: 'Name',
field: 'name'
},
{
name: 'Type',
field: 'type'
},
{
name: 'Status',
field: 'status'
}
];
this.state = {
faults: []
};
this.parseFields = this.parseFields.bind(this);
}
parseFields() {
let parsedFields = [];
this.props.fields.forEach((field) => {
const typeSelected= this.props.types.find(element => element.key === field.type) || '';
let parsedField = Object.assign({}, field);
parsedField['type'] = typeSelected.type;
parsedFields.push(parsedField);
});
this.setState({data: parsedFields});
}
componentDidMount() {
this.parseFields();
}
componentWillReceiveProps() {
this.parseFields();
}
render() {
return(
<Table
data={this.state.faults}
columns={this.columns}
handleClick={this.props.handleClick}
/>
);
}
}
export default FaultList;
这是负责处理在父组件中处理的数据提取的代码:
componentDidMount() {
this.faultsRef= ref.child('faults');
this.faultsRef.on('value', (snap) => {
let faults= [];
snap.forEach((child) => {
let fault= child.val();
let key = child.key;
const finalFault = update(fault, {$merge: {key}});
faults.push(finalFault);
});
this.setState({faults});
});
get('types')
.then((types) => {
this.setState({types});
});
}
get函数的代码是:
function get(node) {
return ref.child(node).once('value')
.then((snap) => {
let list = [];
snap.forEach((child) => {
let object = child.val();
let key = child.key;
const finalObject = update(object , {$merge: {key}});
list .push(finalObject);
});
return list;
});
}
我注意到一些非常奇怪的事情。如果我在父组件的'componentDidMount'中重新排序一些代码,我首先检索类型列表然后获取错误列表,第一次重新渲染是正确完成但是类型没有被解析所以我'我的桌子上留下了空单元格。
答案 0 :(得分:0)
我认为您应该在this.state.data
组件而不是Table
上使用this.state.faults
:
<Table
data={this.state.data}
columns={this.columns}
handleClick={this.props.handleClick}
/>
答案 1 :(得分:0)
如果我正确理解您的组件,FaultList
不会异步执行任何操作,只需从父级接收道具即可。鉴于此,您可以通过使FaultList
无状态并仅直接解析render
中的数据来简化操作。每当组件接收到新的道具时,组件将重新渲染(即:render
将被调用),并且数据将被重新解析。
class FaultList extends React.Component {
constructor(props) {
super(props);
this.columns = [
...
];
this.parseFields = this.parseFields.bind(this);
}
// You no longer need `componentDidMount` and `componentWillReceiveProps`
parseFields() {
let parsedFields = [];
this.props.fields.forEach((field) => {
const typeSelected= this.props.types.find(element => element.key === field.type) || '';
let parsedField = Object.assign({}, field);
parsedField['type'] = typeSelected.type;
parsedFields.push(parsedField);
});
// Note: we are now returning the value instead of setting `state`.
return parsedFields;
}
render() {
return(
<Table
data={this.parseFields()}
columns={this.columns}
handleClick={this.props.handleClick}
/>
);
}
}
export default FaultList;
答案 2 :(得分:0)
我发现了问题所在。正如Bartek提到Table组件应该具有对状态的引用所以我所要做的就是将parseField移动到父组件并在每次firebase检索新数据时调用它。这是代码:
class FaultsView extends React.Component {
constructor(props) {
super(props);
this.faultsRef = null;
this.state = {
faults: [],
parsedFaults: [],
types: []
};
this.parseFields = this.parseFields.bind(this);
}
componentDidMount() {
get('types')
.then((types) => {
this.setState({types});
});
this.faultsRef = ref.child('faults');
this.faultsRef.on('value', (snap) => {
let faults= [];
snap.forEach((child) => {
let fault= child.val();
let key = child.key;
const finalFault = update(fault, {$merge: {key}});
faults.push(finalFault);
});
this.setState({faults});
// This was the fix!
this.parseFields();
});
}
componentWillUnMount() {
this.faultsRef.off();
}
parseFields() {
let parsedFields = [];
this.props.fields.forEach((field) => {
const typeSelected= this.props.types.find(element => element.key === field.type) || '';
let parsedField = Object.assign({}, field);
parsedField['type'] = typeSelected.type;
parsedFields.push(parsedField);
});
this.setState({data: parsedFields});
}
render() {
return (
<div>
<FaultList
faults={this.state.parsedFaults}
handleClick={this.handleClick}/>
</div>
);
}
}
export default FaultsView;