在我的应用中,我正在使用:
"devDependencies": {
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-es2016": "^6.24.1",
"babel-preset-react": "^6.24.1",
"bootstrap": "^4.0.0",
"browser-sync": "^2.24.5",
"browser-sync-webpack-plugin": "^2.2.2",
"cross-env": "^5.1",
"jquery": "^3.2",
"laravel-mix": "^2.0",
"popper.js": "^1.12",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0",
"uuid": "^3.3.2"
},
在redux端,我有以下设置: store.js:
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleware = [thunk];
const store = createStore(rootReducer, initialState, applyMiddleware(...middleware));
export default store;
rootReducer是:
import {combineReducers} from 'redux';
import menuReducer from './menuReducer';
const rootReducer = combineReducers({
menu: menuReducer
});
export default rootReducer;
其中只有menuReducer可供使用:
import * as types from '../actions/types';
const initialState = {
data: {}
}
export default function(state = initialState, action) {
switch (action.type) {
case types.GET_MENU:
return {
...state,
data: action.payload
}
default:
return state;
}
}
通过单个菜单操作即可获取供稿:
import * as types from './types';
export const getMenu = () => (dispatch) => {
fetch('/admin/json/menu.json')
.then(res => res.json())
.then(data => dispatch({
type: types.GET_MENU,
payload: data
})
)
}
最后是我在组件方面的信息: App.js:
import React from 'react';
import {Provider} from 'react-redux';
import {BrowserRouter} from 'react-router-dom';
import store from '../store';
import SideMenu from './sidemenu';
import Content from './content';
class App extends React.Component {
render() {
return(
<Provider store={store}>
<BrowserRouter basename='/yonetim'>
<div className="h-100">
<SideMenu className="h-100"/>
<Content className="h-100"/>
</div>
</BrowserRouter>
</Provider>
);
};
};
export default App;
以及尝试使用此基本redux实现的组件:
import React, {Fragment} from 'react';
import {v1 as uuid} from 'uuid';
import {connect} from 'react-redux';
import {getMenu} from '../actions/menuActions';
import MenuDropdown from './parts/menu-dropdown';
import MenuItem from './parts/menu-item';
class SideMenu extends React.Component {
componentWillMount() {
this.props.getMenu();
}
render() {
console.log(this.props.menuData);
return(
<header>
<div className="cnt-menu-head">
<h6>{this.props.menuData.heading}</h6>
</div>
<div className="cnt-menu">
<ul className="nav nav-pills flex-column">
{this.props.menuData.sections.map((section, i) => {
if (section.type === 'link') {
let key = uuid();
return <MenuItem key={key} exact={section.exact} linkTo={section.linkTo} linkText={section.linkText}/>
} else if (section.type === 'dropdown') {
let keyedLinks = section.links.map((link) => {
link.key = uuid();
return link;
});
return (
<Fragment key={uuid()}>
<div className="horizontal-separator"></div>
<MenuDropdown linkText={section.linkText} links={keyedLinks}/>
</Fragment>
)
}
})}
</ul>
</div>
</header>
);
};
};
function mapStateToProps(state) {
return {
menuData: state.menu.data
}
}
export default connect(mapStateToProps, {getMenu})(SideMenu);
会发生什么:
我得到了错误:
未捕获的TypeError:无法读取未定义的属性“ map”
参考我的代码中的this.props.menuData.sections.map()
部分。现在有趣的是:
console.log()
时,我看到它们也被两次调用。this.props.menuData
中使用render()
的代码时,渲染功能开始处的console.log(this.props.menuData);
在render()
的第一次运行中打印为空,然后被第二次运行时要使用的实际数据充满。我完全不知道这段代码是怎么回事,或者可能是潜在的原因。任何帮助深表感谢。谢谢。答案 0 :(得分:4)
这里的问题是您正在调用“异步”操作(获取),该操作在获取后分派数据。
因此,将加载您的组件,但是当您的函数(getMenu)将操作分派给Redux时,您的组件将第二次运行。
我可能建议做一个三元处理,它调节menuData使用者的渲染并显示一个加载器:
在渲染器内部:
return this.props.menuData.sections ? (actualCodeGoesHere) : <Loader />
答案 1 :(得分:1)
请确保您没有第一次渲染的数据。有两种方法可以解决此问题: 1.将小节的键设置为menuReducer的initialState。 2.在this.props.menuData.sections.map(…)之前添加一个检测。也许是这样的:this.props.menuData.sections && this.props.menuData.sections.map(…)