2016-04-01 5 views
5

私はReactには本当に新しく、ルートにgetComponentがロードされているときに、「ロード中...」画面をレンダリングする方法を理解できません。 getComponent呼び出しはうまく動作し、コンポーネントを表示しますが、リクエストとレスポンスの間に何かが起こっているというUIへの指示はありません。それは私が把握しようとしているものです。失敗したフォーカス取得時使用して表示する「ロード」コンポーネントを強制しようとした後、またはgetComponent関数内react-routerでgetComponentを呼び出すときのUIの読み込みを表示するには?

import Main from './pages/Main.jsx'; 
import Test from './pages/Test.jsx'; 
import Home from './pages/Home.jsx'; 


var Routes = { 
    path: "/", 
    component: Main, 
    indexRoute: { 
    component: Home 
    }, 
    childRoutes: [ 
    { 
     path: "test", 
     component: Test 
    }, 
    { 
     path: "about", 
     getComponent: function(path, cb) { 
     require.ensure([], (require) => { 
      cb(null, require("./pages/about/About.jsx")); 
     }); 
     } 
    } 
    ] 
}; 

export default Routes; 

、私は多分、私は真/偽に積載状態を設定するReduxのを使用して、私のメインのビューコンポーネントを取得してみてくださいと思いましたロード画面表示する:

import React from 'react'; 
import {connect} from 'react-redux'; 

import NavBar from '../components/Navigation/NavBar.jsx'; 
import Footer from '../components/Footer.jsx'; 
import Loading from './Loading.jsx'; 
import navItems from '../config/navItems.jsx'; 
import setLoading from '../actions/Loading.jsx'; 

var Main = React.createClass({ 
    renderPage: function() { 
    if (this.props.loading) { 
     return (
     <Loading/> 
    ); 
    } else { 
     return this.props.children; 
    } 
    }, 
    render: function() { 
    return (
     <div> 
     <header id="main-header"> 
      <NavBar navigation={navItems}/> 
     </header> 
     <section id="main-section"> 
      {this.renderPage()} 
     </section> 
     <Footer id="main-footer" /> 
     </div> 
    ); 
    } 
}); 

function mapStateToProps(state) { 
    return { 
    loading: state.loading 
    } 
} 

export default connect(mapStateToProps)(Main); 

をこれは私が手動で私が何を探していたものであるアクションを、使用して負荷状態を設定した場合に動作するようです。しかし、(そして、これは本当の問題ではないと思う)私はルータ内からストア/ディスパッチャにアクセスする方法を理解できません。

間違った検索用語を使用しているかどうかわかりませんが、私は完全にアイデアがなく、すべての反応ルータ/レビュックスチュートリアルは私が共通でなければならないと感じているものをスキップするようです問題。

誰でも正しい方向に向けることができます(また、自分が行っていることがベストプラクティスであるかどうかを教えてください)。

EDIT:これをもう少し詳しく解説します。最初のコードブロックで、<Link to="/about">要素をクリックすると、getComponent関数が起動し、About.jsxコンポーネントが遅延ロードされることがわかります。私が抱えている問題は、リンクをクリックした直後に表示される何らかの種類のローディングインジケータ/スピンナを表示する方法を理解することができず、コンポーネントが読み込まれると置き換えられるということです。

MORE編集:私はロード非同期ルートのラッパーコンポーネントを作成しようとしましたし、動作しているようです、しかし、それは本当にハック感じていると私はそれがこれをやって行くための正しい方法ではないと確信しています。ルートコードは次のようになります。

import Main from './pages/Main.jsx'; 
import Test from './pages/Test.jsx'; 
import Home from './pages/Home.jsx'; 
import AsyncRoute from './pages/AsyncRoute.jsx'; 


var Routes = { 
    path: "/", 
    component: Main, 
    indexRoute: { 
    component: Home 
    }, 
    childRoutes: [ 
    { 
     path: "test", 
     component: Test 
    }, 
    { 
     path: "about", 
     component: AsyncRoute("about") 
    } 
    ] 
}; 

export default Routes; 

AsyncRoute.jsxページには、次のようになります。

import React from 'react'; 

function getRoute(route, component) { 
    switch(route) { 
    // add each route in here 
    case "about": 
     require.ensure([], (require) => { 
     component.Page = require("./about/About.jsx"); 
     component.setState({loading: false}); 
     }); 
    break; 
    } 
} 

var AsyncRoute = function(route) { 
    return React.createClass({ 
    getInitialState: function() { 
     return { 
     loading: true 
     } 
    }, 
    componentWillMount: function() { 
     getRoute(route, this); 
    }, 
    render: function() { 
     if (this.state.loading) { 
     return (
      <div>Loading...</div> 
     ); 
     } else { 
     return (
      <this.Page/> 
     ); 
     } 
    } 
    }); 
}; 

export default AsyncRoute; 

誰もがより良いアイデアを持っている場合、私に知らせてください。私はルータの中から

をストア/ディスパッチャにアクセスする方法を見つけ出すことはできません

なしがあります:私はここに、この上でいくつかの光を当てることができるかどうかを見てみましょう

答えて

0

OK、そのAFAIKを行う必要があります。すべてのルートを指定し、上記のように各ルートに応答するコンポーネントをリストし、各コンポーネントをレデックスストアに接続することができます。接続のために、あなたのmapStateToProps機能は、このように、はるかに簡単な方法で書くことができます。

export default connect(state => state)(Main); 

loading状態について:私は遅いローディングのコンポーネントを持っていると表示するには、間違った方向への一歩だと思いますロード中に待機中のインジケータ。バックエンドからすべてのデータを非同期にロードする高速ロードコンポーネントを使用し、データがまだ利用できない間は、コンポーネントは待機インジケータをレンダリングします。データが利用可能になると、それを表示することができます。それは基本的に、2回目の編集でスケッチしたものです。

データが表示されていない - >読み込み中の画面/データが表示されている - >実際の画面を表示すると、さらに効果的です。こうすることで、読み込み中のフラグが同期しなくなった場合の問題を回避できます。

ラッパーを汎用化するのではなく、読み込み画面用のスタンドアロンコンポーネントを作成して、個々のコンポーネントが必要と感じるたびに表示します。 (一般的な方法でこれを処理することは困難であると考えられるので、これらのニーズは、異なっている。)このような何か:

var Page = function(route) { 
    return React.createClass({ 
    getInitialState: function() { 
     // kick off async loading here 
    }, 
    render: function() { 
     if (!this.props.myRequiredData) { 
     return (
      <Loading /> 
     ); 
     } else { 
     return (
      // display this.props.myRequiredData 
     ); 
     } 
    } 
    }); 
}; 
+0

おかげで、それは両方のだが、現時点ではより多くの私のコードの問題と、私は私を感じて、コンポーネント内のデータの読み込みではなく、コンポーネントの自己でありますそれを解決しようと間違った方向に行ってしまった可能性があります。私は私の質問を編集して明確にしようとします。 –

+0

About.jsxコンポーネントの読み込みに時間がかかるのはなぜですか?同期して何かをロードしていますか?そのコンポーネントのスケッチを追加できますか? – Nicole

+0

About.jsxは、テキストのページをレンダリングするだけです(レンダリング機能を持つコンポーネントの1つです)。しかし、私は70以上のルートを持つ巨大なアプリケーションを作成する予定です。シンプルなページであれば、他のものは依存関係のヒープを引くより複雑な巨大なものになるので、私はさらに先に進む前にこの非同期のものを最初に見つけ出したいと思います。代わりに非同期読み込みを行うラッパーコンポーネントを作ることができると思っていましたが、それを行う「正しい」方法のようには感じられません。 –

1

私はこの考え出したと思います。それは、物事について正しい方法であるかもしれないし、そうでないかもしれないが、うまくいくようである。また私はなぜこれについて以前考えなかったのか分からない。

まずアップ、独自のファイル(store.jsx)に私のCREATESTOREコードを移動するので、私は、メインエントリポイントにだけでなく、私のRoutes.jsxファイルにインポートすることができます

import {createStore} from 'redux'; 
import rootReducer from '../reducers/Root.jsx'; 

var store = createStore(rootReducer); 

export default store; 

Root.jsx私はその番組の基本的なコンポーネントを作った

import {combineReducers} from 'redux'; 
import user from './User.jsx'; 
import test from './Test.jsx'; 

var loading = function(state = false, action) { 
    switch (action.type) { 
    case "load": 
     return true; 
    case "stop": 
     return false; 
    default: 
     return state; 
    } 
}; 


export default combineReducers({ 
    user, 
    test, 
    loading 
}); 

:(それは醜い混乱だが、私はちょうど基本的なレベルで動作何かを取得しようとしているし、私はそれをきれいにします)、このようになります。 Reduxストアの「読み込み」の値によってロード/ロードされます:

import React from 'react'; 
import {connect} from 'react-redux'; 

var Loading = React.createClass({ 
    render: function() { 
    if (this.props.loading) { 
     return (
     <h1>Loading</h1> 
    ); 
    } else { 
     return (
     <h1>Loaded</h1> 
    ); 
    } 
    } 
}); 

export default connect(state => state)(Loading); 

そして今、私のRoutes.jsxファイルには、この(私はReduxのストアをインポートした注意してください)のようになります。

import Main from './pages/Main.jsx'; 
import Test from './pages/Test.jsx'; 
import Home from './pages/Home.jsx'; 
import store from './config/store.jsx'; 

var Routes = { 
    path: "/", 
    component: Main, 
    indexRoute: { 
    component: Home 
    }, 
    childRoutes: [ 
    { 
     path: "test", 
     component: Test 
    }, 
    { 
     path: "about", 
     getComponent: function(path, cb) { 
     store.dispatch({type: "load"}) 
     require.ensure([], (require) => { 
      store.dispatch({type: "stop"}); 
      cb(null, require("./pages/about/About.jsx")); 
     }); 
     } 
    } 
    ] 
}; 

export default Routes; 

これは動作するようです。 <Link/>をクリックして/ aboutルートに移動すると、アクションが送出されて、メインストアの「ロード中」状態がtrueに設定されます。これにより、<Loading/>コンポーネントが自動的に更新されます(私は最終的にウィンドウの角にスピナーを描くことを想定しています)。その奇妙なrequire.ensure([])関数は、空白のコード分割を行うためにwebpackを取得するために実行され、コンポーネントが読み込まれると、読み込み状態をfalseに設定する別のアクションが送出され、コンポーネントがレンダリングされます。

私はまだReactには新しく、これはうまくいくと思われますが、それが正しい方法であるかどうかはわかりません。もし誰かがより良い方法を持っているなら、チャイムでチャットしてください!

1

@David Mと同じアプローチに従って、ロードリデューサとディスパッチをラップする関数を実装しました。

ストアの作成を除くと管理次のように、それらは基本的に次のとおり

loadingReducer:フェッチする残りのモジュールが存在している間loadingQueueは、ネストされたため、アクティブロードメッセージを保持する方法

// ------------------------------------ 
// Constants 
// ------------------------------------ 
export const LOADING = 'LOADING' 

// ------------------------------------ 
// Actions 
// ------------------------------------ 
const loadQueue = [] 
export const loading = loading => { 
    if (loading) { 
     loadQueue.push(true) 
    } else { 
     loadQueue.pop() 
    } 

    return { 
     type: LOADING, 
     payload: loadQueue.length > 0 
    } 
} 

export const actions = { 
    loading 
} 

// ------------------------------------ 
// Action Handlers 
// ------------------------------------ 

const ACTION_HANDLERS = { 
    [LOADING]: (state, action) => (action.payload) 
} 

// ------------------------------------ 
// Reducer 
// ------------------------------------ 
const initialState = false 
export default function reducer (state = initialState, action) { 
    const handler = ACTION_HANDLERS[action.type] 
    return handler ? handler(state, action) : state 
} 

予告ルート。新しいルートを定義する際に

import { loading } from 'loadingReducer' 

const withLoader = (fn, store) => { 
    return (nextState, cb) => { 
     store.dispatch(loading(true)) 

     fn(nextState, (err, cmp) => { 
      store.dispatch(loading(false)) 
      cb(err, cmp) 
     }) 
    } 
} 

export default withLoader 

今、私たちはwithLoaderを使用して暗黙的にロードするアクションを派遣することができます:

someRoute:

import withLoader from 'withLoader' 
import store from 'store' 

const route = { 
    path: 'mypath', 
    getComponent: withLoader((nextState, cb) => { 
     require.ensure([], require => { 
      cb(null, require('something').default) 
     }, 'NamedBundle') 
    }, store) 
} 
export default route 
+0

あなたのコードを 'store.js'でも共有できますか?どのようにグローバルストアを手に入れますか? – Tieme

0

動的負荷非同期ルータ機能withLoader

require.ensureを使用しています。jsonpネットワークからスクリプトをダウンロードする。 遅いネットワークのために、いつかは、UIブロック、画面はまだプレビュー反応コンポーネントを表示しています。

@Nicole、は本当に遅いが原因でJSONPの

関連する問題