2017-01-06 15 views
1

Reactコンポーネントで初期データを取得するためのディスパッチを呼び出す最良の方法は何ですか?私の理解は、レンダリングの前にComponentWillMountが呼び出されるということです。だから理論的には、私がComponentWillMountでディスパッチを呼び出すと、レンダリングしてからComponentDidMountを押すまでに、コンポーネントの小道具に自分のデータがあるはずです。私はそれを見ていないよ。React Redux Dispatch

レンダリングが2回呼び出されているのが見えています。コンポーネントが初期化されるときにレンダリングが最初に実行されると、私は小道具のデータにアクセスできません。また、ディスパッチは2番目のレンダリングまで実際に呼び出されないようです。私は基本的に、最初にコンポーネントを設定するときに、ディスパッチを呼び出す最良の方法についていくつかの光を当てたいと考えています。私は本質的に次のようなことをしようとしています。コンテナコンポーネントを使用してデータを送出し、それを小道具として子コンポーネントに渡します。しかし、私はまた、ContainerComponent内のいくつかの状態変数を初期化し、それらをChildComponentにpropsとして渡したいと思っています。問題は、私が初期化したい状態変数が、ディスパッチから返されたデータに依存し、理想的には、ComponentWillMountまたはComponentDidMountで初期化を行うということです。ここで

import React from 'react'; 
import axios from 'axios'; 

import { connect } from 'react-redux'; 
import ChildComponent from './ChildComponent.js'; 

import { getTransactionsAll } from '../actions/actions.js'; 

class ContainerComponent extends React.Component { 
    constructor() { 
    super(); 
    this.state = { 
     acctList:[], 
     acctChecked:[], 
     categoryList:[] 
    } 
} 
    componentWillMount() { 

    console.log("componentWillMount entered"); 

    this.props.get_data(); 
    console.log(this.props.searchProps.transactions_all);//this is undefined meaning the dispatch has not assigned the data yet...?? 

    } 

    componentDidMount() { 
    console.log("componentDidMount entered"); 
    console.log(this.props.searchProps.transactions_all);//this is undefined meaning the dispatch has not assigned the data yet...?? 
} 

    render() { 

    console.log("TransactionManagerContainer render entered"); 
    console.log(this.props.searchProps.transactions_all);//this is undefined the first time around meaning the dispatch has not assigned the data yet...??, but is defined on the second call to render after the dispatch has actually occurred... 

return <ChildComponent 
      data={this.props.searchProps.data}/>; 
} 

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

export default connect(mapStateToProps, {getTransactionsAll})(TransactionManagerContainer); 

は、状態を割り当て、私の減速である:ここでは

import { combineReducers } from 'redux' 

import {GET_TRANSACTIONS } from '../actions/actions.js' 
import {GET_TRANSACTIONS_ALL } from '../actions/actions.js' 

const INITIAL_STATE = { defaultYear: 2016, transactions: []}; 

function get_transactions(state = INITIAL_STATE, action) { 
    // console.log("this is in the reducer: get_transactions"); 
    // console.log(action); 
    switch(action.type) { 
    case GET_TRANSACTIONS: 
     // return { ...state, transactions: action.payload }; 
     return Object.assign({}, state, { 
     transactions: action.payload, 
     selectedYear: action.selectedYear 
     }) 
    default: 
     return state; 
    } 
} 

function get_transactions_all(state = INITIAL_STATE, action) { 
    console.log("this is the value of action in the reducer: get_transactions_all"); 
    console.log(action); 
    switch(action.type) { 
    case GET_TRANSACTIONS_ALL: 
     // return { ...state, transactions: action.payload }; 
     return Object.assign({}, state, { 
     transactions_all: action.payload 
     }) 
     console.log("this is the value of state in the reducer after being set"); 
     console.log(state); 
    default: 
     return state; 
    } 
} 

const rootReducer = combineReducers({ 
    //stateProps: get_transactions, 
    searchProps: get_transactions_all 
}) 

export default rootReducer 

は私のアクションは、次のとおりです。

What is the best way to call a dispatch to get initial data on a React component?

行き方:

import axios from 'axios'; 

export const GET_TRANSACTIONS = 'GET_TRANSACTIONS'; 

export function getTransactions(year) { 
return function(dispatch) { 
    axios.get(`http://localhost:3001/api/transfilter?year=${year}&grouping=2`) 
    .then(response => { 
    dispatch({ 
     type: GET_TRANSACTIONS, 
     payload: response.data, 
     selectedYear: year 
    }); 
    }) 
    .catch((error) => { 
    console.log(error); 
    }) 
} 
} 

export const GET_TRANSACTIONS_ALL = 'GET_TRANSACTIONS_ALL'; 

export function getTransactionsAll(year) { 
return function(dispatch) { 
    axios.get(`http://localhost:3001/api/trans?limit=20`) 
    .then(response => { 

    dispatch({ 
     type: GET_TRANSACTIONS_ALL, 
     payload: response.data 
    }); 
    }) 
    .catch((error) => { 
    console.log(error); 
    }) 
} 
} 
+0

我々はcomponentDidMountでフェッチAPIデータメソッドを呼び出しています。 HTMLテンプレートでコンポーネントをどのように使用していますか? –

+0

フェッチが機能します。すべてが機能します。私はちょうどそれを行うための最善の方法を知り、ディスパッチ "ライフサイクル"をよりよく理解したいと思っています。レンダリングが2回呼び出され、2回目のレンダーが呼び出されるまでデータが利用できないので、フェッチが実際に呼び出されるのはいつかです。 –

+0

ここで 'searchProps'を渡しています。このコンテナの親コンポーネントと 'get_data'関数を表示してください。 – azium

答えて

3

私はあなたの主な質問があると信じて初期データ要求(またはAJAX要求通常はts)は、ライフサイクルイベントのcomponentDidMountに入る必要があります。

は、このためのいくつかの理由があり、ここでは二つの重要な以下のとおりです。

  1. ファイバーは、のリアクト和解アルゴリズムの次の実装は、開始およびパフォーマンス上の利点のために、必要に応じてレンダリングを停止する能力を持つことになります。これのトレードオフの1つは、AJAXリクエストを作成する意味がある他のライフサイクルイベントであるcomponentWillMountが「非決定的」であるということです。これが意味することは、Reactが、必要なときにいつでも、componentWillMountをさまざまな時に呼び出すことができるということです。これは明らかにAJAXリクエストのための悪い公式となるでしょう。

  2. コンポーネントがマウントされる前にAJAXリクエストが解決されないことを保証することはできません。そうした場合、それはアンマウントされたコンポーネントにsetStateを実行しようとしていることを意味します。これは動作しないだけでなく、Reactがあなたに叫ぶでしょう。 componentDidMountでAJAXを実行すると、更新するコンポーネントがあることが保証されます。

クレジット:私はhereから、議論hereもあることを学びました。

次に、あなたが上げてきたと私はすべてを答えるのは難しいだろうが、私はほとんど網羅しようとするでしょう小さな疑問がたくさんあります。

  • は、あなたが今、上記を読んだ後あなたのデータがundefinedで、componentWillMountcomponentDidMountである理由を理解する必要があります。これは単にデータがまだ届いていないためです。
  • 通常、コンポーネントの最初のレンダリング中にデータがundefinedであることが正常です。初期レンダリングはデータの到着前に行われます。
  • 2番目のレンダリング中にデータが定義されるのは正常です。 dispatchは、非同期データフェッチをトリガします。データの直後にreducerがヒットし、コンポーネントが再レンダリングされます(2回目の再レンダリング)。
  • データが存在する場合は、親コンポーネントrenderのメソッドでメインコンポーネントの子コンポーネントにデータチェックが必要な場合、条件付きで内部コンポーネントを渡します(データが存在する場合のみ)。これと同じように:それは作業する必要があるので、反応/ nuclearjsプロジェクトで

    class ContainerComponent extends React.Component { 
        // ... omitted for brevity 
    
        render() { 
        return (
         { this.props.searchProps.data ? 
          <ChildComponent 
          data={this.props.searchProps.data} /> 
          : <p>Loading</p> 
         } 
        ); 
        } 
    } 
    
+0

概念の説明をありがとう。それは理にかなっている。だから私は上記のレンダリングをコピーして貼り付けてしまい、エラーが出ます: '111 |リターン( > 112 | {this.props.searchProps.data |^ 113 | 115 |:

読み込み

'されていませんコメントを整形する方法がわからないことがありますが、本来、this.propsへの最初の呼び出し時に構文エラーが発生しました。予期しないトークンがあります。 –

+0

あなたは歓迎です。 'this.props.searchProps'が定義されていないために問題が発生している可能性があります。デフォルトで' props'をデフォルトに設定することは良い習慣ですが、そうでないと常に 'undefined '最初のレンダリング中に。[デフォルトの小道具を宣言](http://stackoverflow.com/documentation/reactjs/6371/react-createclass-vs-extends-react-コンポーネント/ 25321/declare-default-props-and-proptypes#t = 201701071958593048809)、問題が解決されているかどうかを確認してください。 –

+0

ありがとうございます。私はあなたがあなたが返答した私の他の投稿で示唆したようにそれをしました。また、既定の小道具を設定することもできません。私は困惑している。私のデフォルトの小道具は無視されているようです。私は自分のbabel.rcに行って、2016イニシャライザが設定されていることを確認しました。私は、コンストラクタでデフォルトの小道具を設定する静的な方法と、Component.defaultPropsを使用してクラス外で行うことの両方を試みました。どちらもまだ私はまだ未定義になっているので、動作するように見えます。 –

関連する問題