我正在使用React和Redux。我希望Redux存储客户端信息(视口尺寸,浏览器名称和版本,操作系统等)。我已经设置了reducers和actions,并将所有状态映射到<App />
组件的道具。在<App />
组件内部有一个<Header />
组件,它将道具传递给<NavigationBar />
组件。 <NavigationBar />
然后映射道具以渲染<NavigationItems />
,然后生成以下导航栏:
Home | About us | Apply | News | Login
但是由于<App />
组件内部的props映射,每次用户调整视口大小时,Redux存储库中的状态更改,导致<App />
中的props更改,当然,React重新呈现整个导航栏会产生以下意外行为:
Home | Home | About us | Apply | News | Login
要么
About us | Home | About us | Apply | News | Login
简而言之,<NavigationBar />
返回的项目数量应该超出预期。我已经包含了代码结构以便更好地说明:
Store (contains client info)
---> <App /> (map states, dispatchers from store to props)
---> <Header /> (functional component acts as container, pass navigation settings as props down to <NavigationBar />)
---> <NavigationBar /> (receives props from <Header /> and renders <NavigationItems /> component with props from <Header /> using map() function)
---> <NavigationItems /> (renders navigation items based on the props)
我还包含了代码以防万一有人需要它:
rootTypes.js(定义动作类型)
export const tUpdateViewport = 'updateViewport'
rootActions.js(定义调度程序)
import { tUpdateViewport } from './rootTypes';
export const aUpdateViewport = () => ({type: tUpdateViewport })
rootReducer.js(定义app reducer并将其与其他人合并)
import { tUpdateViewport } from './rootTypes';
import { combineReducers } from 'redux';
const appStates = {
viewportWidth: document.documentElement.clientWidth,
viewportHeight: document.documentElement.clientHeight,
};
const appReducer = (states = appStates, action) => {
switch(action.type) {
case tUpdateViewport:
return {
...states,
viewportWidth: document.documentElement.clientWidth,
viewportHeight: document.documentElement.clientHeight,
};
default:
return states;
}
};
export default combineReducers({
app: appReducer,
})
App.js(定义<App />
组件并呈现<Header />
)
import React from 'react';
import Header from './components/container/header/Header';
import * as actions from './rootActions';
import { connect } from 'react-redux';
const mapStatesToProps = states => ({
browserInfo: states.app
});
class App extends React.Component {
componentDidMount = () => {
window.addEventListener('resize', this.props.aUpdateViewport, false);
};
componentWillUnmount = () => {
window.removeEventListener('resize', this.props.aUpdateViewport, false);
};
render = () => {
return (
<Header />
);
};
}
export default connect(mapStatesToProps, actions)(App)
Header.js(定义<Header />
组件并呈现<NavigationBar />
组件)
import React from 'react';
import NavigationBar from '../../presentational/header/NavigationBar';
import { Container, Grid, Row, Col } from '../../../css/Grid.css';
import { Header as Navigator } from '../../../css/Layout.css';
import logo from '../../../media/images/logo.png';
const Header = props => {
return (
<Navigator>
<Container>
<header>
<Grid>
<Row>
<Col>
<a href="#"><img src={logo} alt="CKY-UK Logo" /></a>
</Col>
<Col stretchWidth>
<Grid>
<Row stretchHeight alignEnd="md" alignMiddle="md">
<NavigationBar settings={{
items:
[
{
title: 'Home',
link: '/'
},
{
title: 'About us',
dropdownHierarchy: 'parents',
icons: [{
title: 'chevron-down',
iconPos: 'afterText'
}],
items: [{
title: 'Leadership Team',
link: '#leadership-team'
},
{
title: 'Star players',
link: '#star-players'
}]
},
{
title: 'Apply',
link: '#apply'
},
{
title: 'News',
link: '#news'
},
{
title: 'Login',
link: '#login',
icons: [{
title: 'sign-in-alt',
iconPos: 'beforeText'
}],
}
]
}} />
</Row>
</Grid>
</Col>
</Row>
</Grid>
</header>
</Container>
</Navigator>
);
};
export default Header
NavigationBar.js(定义<NavigationBar />
组件并映射道具以渲染<NavigationItems />
组件)
import React from 'react';
import NavigationItems from './NavigationItems';
import { uniqID } from '../../../common/Functions';
import { Row } from '../../../css/Grid.css';
const NavigationBar = props => {
const settings = props.settings;
return (
<nav>
<ul>
<Row>
{settings.items.map((contents, index) =>
<NavigationItems settings={{...contents}} isDropdown={contents.items ? true : false} key={uniqID()} />
)}
</Row>
</ul>
</nav>
);
};
export default NavigationBar
NavigationItems.js(定义<NavigationItems />
并呈现导航栏)
import React from 'react';
import { uniqID } from '../../../common/Functions';
import { NavLi, NavItem, Dropdown } from '../../../css/Navigation.css';
import { Icon } from '../../../css/Common.css';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
class NavigationItems extends React.Component {
constructor(props) {
super(props);
this.state = {
dropdownOpened: false,
navLiWidth: null,
navLiHeight: null
}
}
handleClick = e => {
e.preventDefault();
this.setState(prevState => ({
dropdownOpened: !prevState.dropdownOpened
}));
};
handleClickOutside = e => {
const target = e.target;
if (!this.NavLi.contains(target)) {
this.setState({
dropdownOpened: false
})
}
}
componentDidMount = () => {
const navLiWidth = this.NavLi.clientWidth,
navLiHeight = this.NavLi.clientHeight;
this.setState({
navLiWidth: navLiWidth,
navLiHeight: navLiHeight
});
document.addEventListener('click', this.handleClickOutside, false);
}
componentWillUnmount = () => {
document.removeEventListener('click', this.handleClickOutside, false);
}
render = () => {
const settings = this.props.settings,
isDropdown = this.props.isDropdown
return (
<NavLi isDropdown={isDropdown} innerRef={x => this.NavLi = x}>
<NavItem href={settings.link || '#'} onClick={isDropdown ? this.handleClick : null}>
{settings.icons && settings.icons.filter(contents => contents.iconPos === 'beforeText').map(contents =>
<Icon beforeText key={uniqID()}><FontAwesomeIcon icon={contents.title} fixedWidth /></Icon>
)}
{settings.title}
{settings.icons && settings.icons.filter(contents => contents.iconPos === 'afterText').map(contents =>
<Icon afterText key={uniqID()}><FontAwesomeIcon icon={contents.title} fixedWidth /></Icon>
)}
</NavItem>
{isDropdown &&
<Dropdown hierarchy={settings.dropdownHierarchy} opened={this.state.dropdownOpened} topPos={this.state.navLiHeight} leftPos={this.state.navLiWidth} desPos={10} startPos={50}>
{settings.items.map(contents =>
<NavigationItems settings={{...contents}} isDropdown={contents.items ? true : false} key={uniqID()} />
)}
</Dropdown>
}
</NavLi>
);
};
};
export default NavigationItems
我怎样才能解决这个问题?谷歌搜索映射问题,但没有找到所需的结果。任何帮助将不胜感激。
我猜uniqID
只是一个随机数发生器?
key
prop特别存在为非随机的。将它更改为每个循环一致且唯一的值,如title
,这可能会解决您的问题。