Я изменяю старую версию проекта response + redux side, поскольку бэкэнда нет, я могу только имитировать api resopnd.
Проблема, с которой я столкнулся, состоит в том, что у меня есть домашний интеллектуальный компонент, который будет имитировать 2 действия API вызова, getHomeAllData и getProfileAllData в течение цикла componentDidMount,
Все процессы API вызова и редуктора являются нормальными, и журнал также отображается правильно, но 2 реквизита, которые должны быть получены в Цикл дома getDerivedStateFromProps всегда будет на 1 меньше. Через журнал я обнаружил, что когда на редукс-коннект получено 2 редуктора, при возврате состояния один из mapStatetoProps станет пустым объектом, и сообщение об ошибке не появится. Если он не будет выполнен в одно и то же время, каждый вызов сможет нормально получать повторное открытие, что меня очень смущает.
combReducers не может обработать состояние соединения, возвращаемое одновременно? Или что-то не так с моей конфигурацией?
Прикрепите мой код, надеюсь, каждый сможет помочь, благодарен.
Домашний контейнер
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {HomeRedux, ProfileRedux} from '../../Redux/Modules';
class Home extends Component {
constructor() {
super();
this.state = {
getHomeRecommendStatus: false,
getProfileChannelStatus: false,
homeRecommendData: [],
profileChannelData: [],
};
}
componentDidMount() {
this.getHomeAllData();
this.getProfileAllData();
}
static getDerivedStateFromProps(nextProps) {
switch (nextProps.action.type) {
case HomeRedux.HomeRecommendActions.getHomeRecommendSuccess:
return {getHomeRecommendStatus: true, homeRecommendData: nextProps.action.payload.items};
case ProfileRedux.ProfileChannelActions.getProfileChannelDataSuccess:
return {getProfileChannelStatus: true, profileChannelData: nextProps.action.payload.items};
default:
break;
}
return null;
}
getHomeAllData = () => {
this.props.HomeActionsCreator.simulationGetHomeData(request);
};
getProfileAllData = () => {
this.props.ProfileActionsCreator.simulationGetProfileData(request);
};
render() {
return (
<div>
<HomeView>
<ContentArea>
{
this.state.getHomeRecommendStatus && this.state.getProfileChannelStatus
? this.state.homeRecommendData.map((item) => {
return (
<VideoItem
key={item.id}
videoItemData={item}
itemClickAction={this.videoItemClick}
/>
);
})
: <UserActionResult userActionResultData={userActionResultData}/>
}
</ContentArea>
</HomeView>
</div>
);
}
}
Home.propTypes = {
HomeActionsCreator: PropTypes.object.isRequired,
PlayActionsCreator: PropTypes.object.isRequired,
};
export default connect(
// Every time the second state received here is empty {}
(state) => {
return {action: state.HomeReducer.action};
},
(dispatch) => {
return {
HomeActionsCreator: bindActionCreators(HomeRedux.HomeActionsCreator, dispatch),
ProfileActionsCreator: bindActionCreators(ProfileRedux.ProfileActionsCreator, dispatch)
};
}
)(Home);
Home Redux
import {createAction} from 'redux-actions';
import {ProfileRedux} from '../../../Redux/Modules';
import ApiSimulation from '../../../ApiCenter/Api/ApiSimulation';
export const HomeRecommendActions = {
getHomeRecommendStart: 'GET_HOME_RECOMMEND_START',
getHomeRecommendSuccess: 'GET_HOME_RECOMMEND_SUCCESS',
getHomeRecommendFailed: 'GET_HOME_RECOMMEND_FAILED',
};
const simulationGetHomeData = () => {
return (dispatch) => {
dispatch(createAction(HomeRecommendActions.getHomeRecommendStart)());
dispatch(createAction(HomeRecommendActions.getHomeRecommendSuccess)(ApiSimulation.getSearchHome()));
};
};
export const HomeActionsCreator = {
simulationGetHomeData,
};
export default function HomeReducer(state = {action: ''}, action) {
// Both success actions received here are normal, there is respond data
switch (action.type) {
case HomeRecommendActions.getHomeRecommendSuccess:
case HomeRecommendActions.getHomeRecommendFailed:
case ProfileRedux.ProfileChannelActions.getProfileChannelDataSuccess:
case ProfileRedux.ProfileChannelActions.getProfileChannelDataFailed:
return {action: action};
default:
return state;
}
}
Профиль Redux
import {createAction} from 'redux-actions';
import ApiSimulation from '../../../ApiCenter/Api/ApiSimulation';
export const ProfileChannelActions = {
getProfileChannelDataStart: 'GET_PROFILE_CHANNEL_DATA_START',
getProfileChannelDataSuccess: 'GET_PROFILE_CHANNEL_DATA_SUCCESS',
getProfileChannelDataFailed: 'GET_PROFILE_CHANNEL_DATA_FAILED',
};
const simulationGetProfileData = () => {
return (dispatch) => {
dispatch(createAction(ProfileChannelActions.getProfileChannelDataStart)());
dispatch(createAction(ProfileChannelActions.getProfileChannelDataSuccess)(ApiSimulation.getChannels()));
};
};
export const ProfileActionsCreator = {
simulationGetProfileData
};
export default function ProfileReducer(state = {action: ''}, action) {
switch (action.type) {
case ProfileChannelActions.getProfileChannelDataSuccess:
case ProfileChannelActions.getProfileChannelDataFailed:
return {action: action};
default:
return state;
}
}
Api Simulation
const simulationHome = {
some data...
};
const simulationChannels = {
some data...
};
export default class ApiSimulation {
static getSearchHome() {
return simulationHome;
}
static getChannels() {
return simulationChannels;
}
}
Комбинированные редукторы
import {combineReducers} from 'redux';
import ProfileReducer from '../Redux/Modules/Profile/ProfileRedux';
import HomeReducer from '../Redux/Modules/Home/HomeRedux';
const RootReducer = combineReducers({
ProfileReducer,
HomeReducer,
});
export default RootReducer;
Redux Store
import {createStore, applyMiddleware} from 'redux';
import reduxThunk from 'redux-thunk';
import RootReducer from '../Redux/RootReducer';
const ReduxStore = createStore(RootReducer, applyMiddleware(reduxThunk));
export default ReduxStore;
Страница загружается
I Использовали реактивную нагрузку
import React from 'react';
import Loadable from 'react-loadable';
const LoadingPage = () => {
return (<div>Loading...</div>);
};
export const Home = Loadable({
loader: () => import('./Containers/Home/Home'),
loading: LoadingPage
});
Root index
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import createHistory from 'history/createHashHistory';
import ReduxStore from './Redux/ReduxStore';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import {HashRouter, Router, Switch, Route} from 'react-router-dom';
import {Home} from './page-loadable';
import {Portal} from '../src/Containers/index';
import {Header, ActionAlert} from './Components/Layout';
const History = createHistory();
const CommonLayout = React.createContext({path: ''});
class CommonLayoutProvider extends Component {
render() {
return (
<CommonLayout.Provider>
<Header/>
<ActionAlert/>
{this.props.children}
</CommonLayout.Provider>
);
}
}
CommonLayoutProvider.propTypes = {
children: PropTypes.object.isRequired
};
render((
<Provider store={ReduxStore}>
<HashRouter>
<Router history={History}>
<div style={{width: '100%', height: '100%'}}>
<Route component={Portal}/>
<Switch>
<CommonLayoutProvider>
<Route path='/home' component={Home}/>
</CommonLayoutProvider>
</Switch>
</div>
</Router>
</HashRouter>
</Provider>
), document.getElementById('app'));
Package. json
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack -p",
"clean": "rimraf dist/*",
"dev": "webpack-dev-server --devtool eval --progress --watch --hot --mode production",
"prd": "npm run clean && webpack --mode production"
},
"author": "Hsien",
"license": "ISC",
"dependencies": {
"@ant-design/icons": "latest",
"@types/gapi.client": "^1.0.1",
"antd": "^3.22.0",
"axios": "^0.18.0",
"final-form": "^4.12.0",
"gapi-client": "0.0.3",
"history": "^4.7.2",
"is_js": "^0.9.0",
"moment": "^2.24.0",
"prop-types": "^15.6.2",
"react": "^16.4.2",
"react-dom": "^16.4.2",
"react-google-authorize": "^1.0.4",
"react-loadable": "^5.5.0",
"react-player": "^1.11.0",
"react-redux": "^5.0.7",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router-redux": "^4.0.8",
"redux": "^4.0.0",
"redux-actions": "^2.6.1",
"redux-thunk": "^2.3.0",
"styled-components": "^3.4.6",
"webpack-hashed-module-id-plugin": "^0.1.4"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-eslint": "^9.0.0",
"babel-loader": "^7.1.5",
"babel-plugin-import": "^1.12.2",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-env": "^1.7.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"brotli-webpack-plugin": "^1.1.0",
"clean-webpack-plugin": "^0.1.19",
"compression-webpack-plugin": "^2.0.0",
"css-loader": "^1.0.0",
"eslint": "^5.5.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-loader": "^2.1.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-react": "^7.11.1",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^2.0.0",
"hard-source-webpack-plugin": "^0.13.1",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.4.5",
"moment-locales-webpack-plugin": "^1.1.0",
"node-sass": "^4.9.3",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"style-ext-html-webpack-plugin": "^3.4.7",
"style-loader": "^0.23.0",
"uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.1.1",
"webpack": "^4.17.1",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.7"
}
}