gpt4 book ai didi

reactjs - 我的 Redux 状态发生了变化,为什么 React 没有触发重新渲染?

转载 作者:行者123 更新时间:2023-12-03 13:00:14 24 4
gpt4 key购买 nike

我正在尝试设计一个通知组件,在某些情况下(例如连接问题、成功修改等)会出现通知。

我需要通知在几秒钟后消失,因此我触发状态更改,从通知的 componentDidMount 内的 setTimeout 中删除 Redux 状态的通知。

我可以看到状态确实发生了变化,但 React-Redux 没有重新渲染父组件,因此通知仍然出现在 DOM 上。

这是我的 Redux reducer :

const initialState = {
notifications: []
}

export default function (state = initialState, action) {
switch(action.type) {
case CLEAR_SINGLE_NOTIFICATION:
return Object.assign ({}, state, {
notifications: deleteSingleNotification(state.notifications, action.payload)
})
case CLEAR_ALL_NOTIFICATIONS:
return Object.assign ({}, state, {
notifications: []
})
default:
return state
}
}

function deleteSingleNotification (notifications, notificationId) {
notifications.some (function (notification, index) {
return (notifications [index] ['id'] === notificationId) ?
!!(notifications.splice(index, 1)) :
false;
})

return notifications;
}

和我的 React 组件(MainNotification):

/* MAIN.JS */
class Main extends Component {

renderDeletedVideoNotifications() {
console.log('rendering notifications');
const clearNotification = this.props.clearNotification;
return this.props.notifications.map((notification)=> {
return <Notification
key={notification.id}
message={notification.message}
style={notification.style}
clearNotification={clearNotification}
notificationId={notification.id}
/>
});
}

render() {
console.log('rerendering');
return (
<div className="_main">
<Navbar location={this.props.location} logStatus={this.props.logStatus}
logOut={this.logout.bind(this)}/>
<div className="_separator"></div>
{this.props.children}
<BottomStack>
{this.renderDeletedVideoNotifications()}
</BottomStack>
</div>
);
}

}

function mapStateToProps(state) {
return {logStatus: state.logStatus, notifications: state.notifications.notifications};
}

function mapDispatchToProps(dispatch) {
return bindActionCreators({checkLogStatus, logOut, clearNotification, clearAllNotifications}, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(Main);

/* NOTIFICATION.JS */

export default class Notification extends Component{
constructor(props){
super(props);
this.state = {show: true}
}

componentWillReceiveProps(nextProps){
if(nextProps.message){
this.setState({show: true});
}
}

clearNotification(notificationId){
this.props.clearNotifications(notificationId);
}

componentDidMount(){
console.log('notification mount');
setTimeout(()=>{
console.log('timed out');
this.props.clearNotification(this.props.notificationId);
}, 1000);
}

closeNotification(){
this.props.clearNotification(this.props.notificationId);
this.setState({show: false});
}

render(){
const notificationStyles = () =>{
if (this.props.style === "error"){
return {backgroundColor: 'rgba(152, 5, 19, 0.8)'}
}
return {backgroundColor: 'rgba(8, 130, 101, 0.8)'}
};

if(!this.state.show){
return null;
}
return (
<div className="notification" style={notificationStyles()}>
<div className="notificationCloseButton" onClick={this.closeNotification.bind(this)}>
<i className="material-icons">close</i>
</div>
{this.props.message}
</div>
)
}

};

最佳答案

您已经正确连接了所有内容,但您缺少 Redux 的一个关键概念:

使用 Redux,您永远不会改变状态的任何部分。

来自Redux guide :

Things you should never do inside a reducer:

  • Mutate its arguments;
  • Perform side effects like API calls and routing transitions;
  • Call non-pure functions, e.g. Date.now() or Math.random().

deleteSingleNotification 中,您使用 .splice 从数组中删除旧通知。相反,您需要返回一个全新的数组,其中缺少不需要的通知。最简单的方法是使用 .filter 函数:

function deleteSingleNotification(notifications, notificationId){
return notifications.filter (notification => {
return notification.id !== notificationId
}
}
Here is a JSBin with your working notification system!<小时/>

这就是为什么它有效:React-Redux 的工作是在 Redux 存储的特定部分发生更改时更新您的组件。它对状态树的每个部分使用 === 测试来了解是否有任何变化。

当您使用 .splice 等内容更改状态时,它会检查并认为没有任何不同。

这是一个演示该问题的示例:

var array = [ 'a', 'b', 'c' ]

var oldArray = array

array.splice (1, 1) // cut out 'b'

oldArray === array // => true! Both arrays were changed by using .splice,
// so React-Redux *doesn't* update anything

相反,React-Redux 需要我们这样做:

var array = [ 'a', 'b', 'c' ]

var oldArray = array

array = array.filter (item, index => index !== 1) // new array without 'b'

oldArray === array // false. That part of your state has changed, so your
// componenet is re-rendered

出于性能原因,Redux 使用此方法。循环遍历一棵大状态树以查看是否一切都相同需要很长时间。当您保持树不可变时,只需要===测试,并且过程变得更加容易。

关于reactjs - 我的 Redux 状态发生了变化,为什么 React 没有触发重新渲染?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39513753/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com