我正在使用redux和react-router。我也在加载路由之前进行一次API调用来加载数据。从技术上讲,我的数据应首先加载,然后我的路线应该加载。但是我发现它首先加载路由然后它从API加载数据。以下是代码详情。
index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from 'react-redux';
import {ReduxRouter} from "redux-react-router";
import {Route} from "react-router"
import createBrowserHistory from "history/lib/createBrowserHistory"
import configureStore from './store';
import App from "./containers/App";
import Home from "./components/Home";
import Countries from "./components/Countries";
import {fetchData} from './actions/actions';
const history = new createBrowserHistory();
const store = configureStore();
function loadData() {
store.dispatch(fetchData('https://restcountries.eu/rest/v1/all'))
}
ReactDOM.render(
<Provider store={store}>
<ReduxRouter>
<Route history={history}>
<Route component={App}>
<Route path='/' component={Home} />
<Route path='/countries' component={Countries} onEnter={loadData} />
</Route>
</Route>
</ReduxRouter>
</Provider>,
document.getElementById('root')
);
store.js
import { compose , createStore, applyMiddleware } from "redux";
import rootReducer from "./../reducers";
import thunkMiddleware from 'redux-thunk';
import { routerStateReducer, reduxReactRouter } from 'redux-react-router';
import createHistory from 'history/lib/createBrowserHistory';
//Create app store
const createAppStore = compose(
applyMiddleware(thunkMiddleware),
reduxReactRouter({createHistory})
)(createStore);
export default function configureStore( initialState) {
const store = createAppStore(rootReducer, initialState);
return store;
}
reducer.js
import * as types from "./../actions/actionTypes";
import {combineReducers} from "redux";
import {routerStateReducer} from "redux-react-router";
function exampleReducer (state = {isLoading : false, data : [], error:false}, action = null) {
switch (action.type ) {
case types.RECV_ERROR :
return Object.assign({}, {isLoading : false, data: action.data, error: true});
case types.REQ_DATA :
return Object.assign({}, {isLoading : false, error: false});
case types.RECV_DATA :
console.log("Data receive, return immutable store ")
return Object.assign({}, {isLoading : false, data: action.data, error: false});
default:
return state;
}
}
const rootReducer = combineReducers({
router: routerStateReducer,
example: exampleReducer
});
export default rootReducer;
action.js
import * as types from "./actionTypes";
import axios from 'axios';
function requestData() {
return {type: types.REQ_DATA}
};
function receiveData(json) {
return{
type: types.RECV_DATA,
data: json
}
};
export function fetchData(url) {
return function(dispatch) {
//dispatch request for request data to start the spinner
dispatch(requestData());
//Now make the real API call to get the data
return axios( {
url: url,
timeout: 20000,
method: 'get',
responseType: 'json'
}).then(function(response) {
console.log("Data is loaded");
//Data is receive, now call function to aware this
dispatch(receiveData(response.data));
}).catch(function(response){
console.error("Some error happened");
});
}
}
Countries.js
import React from "react";
import {connect} from 'react-redux';
import Country from "./Country";
@connect(state => ({data: state.example.data}))
export default class Countries extends React.Component {
constructor(props) {
super(props);
}
render() {
const {data} = this.props;
console.log("Countries component is loading... data "+ data);
console.log("Countries this.props "+ JSON.stringify(this.props));
return (<div className='container'>
<table className='table table-bordered table-striped'>
<thead>
<tr>
<th>Name</th>
<th>Capital</th>
<th>Population</th>
<th>Domain</th>
</tr>
</thead>
<tbody>
{ data ? data.map(country => { return (<Country key={country.name} country={country} />)}): null}
</tbody>
</table>
</div>
);
};
}
请帮忙。
答案 0 :(得分:3)
您案例的复杂性来自于数据加载是异步操作。
如果希望onEnter函数在触发路由转换之前等待加载的数据,则应使用&#34;回调&#34;论证(如react-router's doc中所述)。
但要知道数据何时加载,您还应该在onEnter函数中监听redux状态的变化。你可以这样写:
function loadData(nextState, replace, callback) {
let unsubscribe;
function onStateChanged() {
const state = store.getState();
if (state.example.data) {
unsubscribe();
callback(); // data is loaded: trigger the route transition
}
}
unsubscribe = store.subscribe(onStateChanged);
store.dispatch(fetchData('https://restcountries.eu/rest/v1/all'));
}
相当复杂,不是吗?!
您应该尝试避免这种模式,原因有以下几种:
这就是为什么您可以以非阻塞的方式更好地在组件的componentDidMount方法中加载数据。在接收加载的数据之前,只需为组件定义初始状态(无数据)。
您将在Redux's real-world example中找到有用的标准模式,其中包含react-router。
答案 1 :(得分:0)
在<App/>
组件中使用componentDidMount或componentWillMount
您可以在路由之前获取数据。