我有一个用react和redux实现的通知弹出系统,每当我想发送带有消息的弹出窗口时,我都会调用redux动作,该动作将改变reducer的状态,并根据reducer的状态显示一个小吃栏。那是在包装子“路由器”组件的路由器组件中,它工作得很好,但是我遇到了用户体验问题,因为每次此通知显示时,它都会重新呈现包含图像的导航栏组件,您可以看到图像重新呈现通知出现时。
这对我来说很奇怪,因为通知操作没有更改包含图像的导航栏的状态,因此我认为不应重新渲染它,因为它没有更改其状态。有人可以给我一些提示吗?
我在redux thunk中使用了getState(),但我对其进行了更改,因为我发现不应使用它,因此不再使用它:https://blog.isquaredsoftware.com/2017/01/idiomatic-redux-thoughts-on-thunks-sagas-abstraction-and-reusability/
然后我重写了导航栏内的shouldComponentUpdate()函数,以验证道具与nextProps不同,因此它不会随着更改而重新渲染,但还没有运气!感谢您的帮助。
export const PrivateRoute = ({
isAuthenticated,
component: Component,
userColors,
messages,
...rest
}) => (
<Route {...rest} component={(props) => (
isAuthenticated ? (
<div className="private-route" style={{
backgroundColor: userColors.bkg ? userColors.bkg : 'linear-gradient(#3366CB, #204080)'
}}>
<NavComponent />
// The snackbar is open when messages.showing is true (this comes from redux store)
<SimpleSnackbar message={messages.currentMessage} open={messages.showing}/>
<Component {...props} />
</div>
) : (
<Redirect to="/" />
)
)} />
);
我可以采取行动进行通知,以便messages.showing变为真,并在小吃栏上显示
this.props.notify(error);
在显示快餐栏之后,它重新渲染了不使用此状态的导航栏组件,并且与显示快餐栏的reducer无关,从而导致导航栏上的图像重新呈现,并且用户感觉不自然。
弹出窗口的操作是:
export const notify = (message) => ({
type: 'NOTIFY',
message
});
export const close = () => ({
type: 'CLOSE'
});
减速器:
const messagesDefaultState = {
currentMessage: '',
showing: false
};
export default (state = messagesDefaultState, action) => {
switch (action.type) {
case 'NOTIFY':
return {
currentMessage: action.message,
showing: true
};
case 'CLOSE':
return messagesDefaultState;
default:
return state;
}
};
并且有一个navbar组件连接到redux存储,并且包含一个化身,每次我从操作中调用通知时,该化身都闪烁。
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import Avatar from 'react-avatar';
import { startLogout } from '../actions/auth';
import { startSetIdiom, startSetIdioms } from '../actions/idiom';
export class NavComponent extends React.Component {
constructor(props) {
super(props);
};
shouldComponentUpdate(nextProps) {
const differentPP = this.props.pp !== nextProps.pp;
const differentName = this.props.name !== nextProps.name;
return differentPP || differentName;
}
componentDidMount() {
if(this.props.idiomData === ''){
this.props.startSetIdioms();
this.props.startSetIdiom('EN');
}
};
burgerToggle = () => {
let linksEl = document.querySelector('.narrowLinks');
if (linksEl.style.display === 'block') {
linksEl.style.display = 'none';
} else {
linksEl.style.display = 'block';
}
};
render() {
return (
<nav>
<div className="navWide">
<div className="wideDiv">
<Link className="header__link header__link_home" to="/dashboard">
<i className="fas fa-home header__icon"></i>
</Link>
<Link className="header__link header__link_title show-for-desktop" to="/dashboard">{this.props.idiomData.navTitle && this.props.idiomData.navTitle || 'Main Menu'} </Link>
<div className="header__end">
<Link to="/changeProfilePic">
//This avatar is flickering everytime I call notify or close from the snackbar actions
<Avatar size="34px" name={this.props.name} src={this.props.pp} round={true}/></Link>
<Link className="nav__link" to="/profilePic">{this.props.idiomData.greeting && this.props.idiomData.greeting || 'Hello, '} {this.props.name && this.props.name || ''}</Link>
<button className="nav__link">{this.props.idiom}</button>
<button className="nav__link" onClick={this.props.startLogout}>{this.props.idiomData.logOut || 'Logout'}</button>
</div>
</div>
</div>
<div className="navNarrow">
<Link className="header__link header__link_home" to="/dashboard">
<i className="fas fa-home header__icon"></i>
</Link>
<div onClick={this.burgerToggle}>
<i className="fa fa-bars fa-2x"></i>
</div>
<div className="narrowLinks">
<Link className="nav__link" to="/profilePic">{this.props.idiomData.greeting ? this.props.idiomData.greeting : 'Hello, ' } {this.props.name && this.props.name || ''}<Avatar size="34px" name={this.props.name} src={this.props.pp} round={true}/></Link>
<button className="nav__link">{this.props.idiom}</button>
<button className="nav__link" onClick={this.props.startLogout}>{this.props.idiomData.logOut || 'Logout'}</button>
</div>
</div>
</nav>
);
};
};
const mapStateToProps = (state) => ({
name: state.dash.userData.name,
pp: state.dash.userData.profilePic,
idiom: state.idiom.currentIdiom ? state.idiom.currentIdiom : 'EN',
idiomData: state.idiom.idiomData.launchpad ? state.idiom.idiomData.launchpad : ''
});
const mapDispatchToProps = (dispatch) => ({
startLogout: () => dispatch(startLogout()),
startSetIdiom: (idiom) => dispatch(startSetIdiom(idiom)),
startSetIdioms: () => dispatch(startSetIdioms())
});
export default connect(mapStateToProps, mapDispatchToProps)(NavComponent);