Javascript 存储区的React/Redux props属性未定义
在我的应用程序中,我正在使用:Javascript 存储区的React/Redux props属性未定义,javascript,reactjs,redux,Javascript,Reactjs,Redux,在我的应用程序中,我正在使用: "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-webp
"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:
从“React”导入React;
从'react redux'导入{Provider};
从“react router dom”导入{BrowserRouter};
从“../store”导入存储;
从“./SideMenu”导入侧菜单;
从“./Content”导入内容;
类应用程序扩展了React.Component{
render(){
返回(
);
};
};
导出默认应用程序;
以及尝试使用此基本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);
import React,{Fragment}来自'React';
从“uuid”导入{v1作为uuid};
从'react redux'导入{connect};
从“../actions/menuActions”导入{getMenu};
从“./parts/菜单下拉列表”导入菜单下拉列表;
从“./parts/菜单项”导入菜单项;
类侧菜单扩展了React.Component{
组件willmount(){
this.props.getMenu();
}
render(){
console.log(this.props.menuData);
返回(
{this.props.menuData.heading}
{this.props.menuData.sections.map((section,i)=>{
如果(section.type==='link'){
让key=uuid();
返回
}else if(section.type==='dropdown'){
让keyedLinks=section.links.map((link)=>{
link.key=uuid();
返回链接;
});
返回(
)
}
})}
);
};
};
函数MapStateTops(状态){
返回{
菜单数据:state.menu.data
}
}
导出默认连接(mapStateToProps,{getMenu})(侧菜单);
发生的事情是:
我得到一个错误:
未捕获的TypeError:无法读取未定义的属性“map”
参考this.props.menuData.sections.map()
我的代码的一部分。有趣的是:
console.log()
放在action和reducer中时,我发现它们也被调用了两次render()
中尝试使用this.props.menuData
的代码时,然后是console.log(this.props.menuData)在渲染函数的开头,代码>在第一次运行render()
时打印为空,然后在第二次运行时填充我试图使用的实际数据。我完全不知道这段代码是怎么回事,或者根本原因是什么。非常感谢您的帮助。谢谢
当然,第一次渲染时没有数据。有两种方法可以解决此问题: 1.将sections键置于menuReducer的初始状态。
2.在此.props.menuData.sections.map(…)之前添加检测。可能是这样的:this.props.menuData.sections&&this.props.menuData.sections.map(…)这里的问题是,您正在调用一个“异步”操作(fetch),该操作在获取数据后调度数据 因此,您的组件将加载,但当您的函数(getMenu)将操作分派到Redux时,您的组件将第二次运行 我可能建议进行三元测试,以调节menuData使用者的渲染并显示加载程序: 在渲染内部:
return this.props.menuData.sections ? (actualCodeGoesHere) : <Loader />
是否返回this.props.menuData.sections?(实际情况):
感谢您的明确解释。你能解释为什么方法的多重调用吗?当我把console.log
放在不同的地方时,我得到了一系列冗余调用:Menu reducer、Menu reducer、Menu action、Running render、Menu reducer、Running renderFirst,我建议使用componentDidMount
而不是componentWillMount
,第二个现在已经被弃用。尝试这样做,并在其中放置一个控制台。log
以测试是否被调用两次,如果是,则与组件或减速机无关,它必须是其他东西,可能是路由器,让我知道console.log是否在componentDidMount
中触发两次,我在componentWillMount
中得到一个log,并且componentDidMount
也有一个,但是render
有两个。我猜你是对的BrowserRouter
可能会在呈现定义了路由的内容之后重新呈现侧菜单
组件。因为我得到…,运行路由器,菜单将挂载,菜单动作,运行渲染,运行内容,菜单确实挂载,菜单缩减器,运行渲染为了避免覆盖动作,您可以从应用程序组件内部调用它。多亏了Redux,这不应该是个问题,它只会填充侧菜单,或者添加一个标志来阻止未来的呼叫,希望这是有帮助的,祝你好运!
return this.props.menuData.sections ? (actualCodeGoesHere) : <Loader />