2017-02-16 4 views
0

私はfirebaseから受け取ったデータを解析し、この新しいデータをコンポーネントに渡そうとしています。データは約束で非同期的に取り出されます。私が遭遇する問題は、componentDidMountを設定してそこのデータを解析する関数を呼び出したとしても、初めてレンダリングされないということです。React:新しい受信データを解析するライフサイクルフックはありますか?

次のように私はfirebaseから受け取るデータは次のとおりです。

faults: [{ 
    name: "Foo", 
    status: "Open" 
    type: "type1" 
}, 
{ 
    name: "Bar", 
    status: "Open" 
    type: "type2" 
}], 
types: [{ 
    key: "type1", 
    type: "Accident" 
}, 
{ 
    key: "type2", 
    type: "Crash" 
}] 

あなたは私がtypesから正しい名前で障害のtypeを置き換えるために、データを解析する必要が見ることができるように。

そうするために、データを解析して状態を設定する関数があります。これは、そのためのコードである:

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

更新2:

私は非常に奇妙な何かに気づいた。親コンポーネントの'componentDidMount 'で少しのコードを並べ替えると、最初に型のリストを取得してフォールトのリストを取得すると、最初の再レンダリングは正しく行われますが、型は解析されないため、私のテーブルに空のセルが残っていました。

+0

コンポーネントコードを投稿できますか?具体的には、 'this.state.data'をどこかで使うべきです。 – ericgio

+0

質問を更新しました。遅れて申し訳ありませんが、コードを翻訳する必要があります。 –

答えて

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; 
+0

はい!それが私が探していたものでした!私は別の仕事を見つけましたが、私はあなたの答えがもっと好きです!どうもありがとう! :D –

0

私はあなたのTableコンポーネントの代わりに、this.state.faultsthis.state.dataを使うべきだと思う:私が正しくあなたのコンポーネントを理解していた場合

<Table 
    data={this.state.data} 
    columns={this.columns} 
    handleClick={this.props.handleClick} 
    /> 
+0

はい、これは最初の再レンダリングを解決しますが、レンダリングする前にデータを解析する必要があります。おそらく、私は正しいライフサイクルで解析を行っていないでしょう。また、解析されたデータで状態を上書きすることもできますが、それが正しい解決策ではないと私は考えています。 –

+0

だから、再レンダリングした後はすべて正常ですか?問題は最初のレンダリングでのみですか?あなたの 'types'データは非同期的にフェッチされるので、コンポーネントが最初にレンダリングされたときに' types'がまだフェッチされていませんか? –

+0

はい、それは問題の一部でした。キーは、親コンポーネントから受け取った小道具を介してFaultListのフィールドを解析することでした。詳細については、受け入れられた回答を参照してください。ありがとう! –

0

問題が何かを発見しました。 Bartekが述べているように、テーブルコンポーネントにはステータスの参照が必要なので、parseFieldsを親コンポーネントに移動して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; 
関連する問題