当前位置: 首页 > 面试题库 >

我的Redux状态已更改,为什么React无法触发重新渲染?

苏昊英
2023-03-14
问题内容

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

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

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

这是我的Redux减速器:

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,您 永远不会 突变的任何部分state

从Redux指南:

在减速器中永远不应该做的事情:

  • 改变其论点;
  • 执行副作用,例如API调用和路由转换;
  • 调用非纯函数,例如Date.now()或Math.random()。

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

function deleteSingleNotification(notifications, notificationId){
    return notifications.filter (notification => {
        return notification.id !== notificationId
    }
}

这是您的工作通知系统的JSBin!

因此,这就是这样做的原因: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使用此方法。遍历一棵大状态树以查看是否所有内容都花了很长时间。当您将树保持 不变时
,只需进行===测试即可,过程变得更加容易。



 类似资料:
  • 我已经初始化了一个数组状态,当我更新它时,我的组件不会重新渲染。以下是一个最低限度的概念证明: 根据这段代码,似乎输入应该包含要开始的数字0,并且无论何时更改,状态也应该更改。在输入中输入“02”后,应用程序组件不会重新渲染。但是,如果我在5秒后执行的onChange函数中添加setTimeout,则表明数字确实已更新。 对为什么组件不更新有什么想法吗? 这是一个带有概念证明的代码沙盒。

  • 我的Redux状态是如何更新的,可以在pokelist.js文件中注销,但是我的状态变量没有设置好,cardList还是一个空数组,我如何正确设置状态?我注销pokelist.js文件中的集合,它首先注销一个空数组,然后是一个包含元素的数组。

  • 我正在尝试使用React Redux。我遇到了这样一种情况:一个连接的组件(Coordinates.jsx)嵌套在另一个连接的组件(Canvas.jsx)中。 源代码https://github.com/RinatRezyapov/Vault-13.git(纱线安装,然后纱线开始) 在父组件画布中。jsx I在componentDidMount()中调度一个操作,该操作不可变地更改状态。 帆布js

  • 有一个案例我很困惑。 我有一个对象redux状态:{show:true,creative:{name:'a',tags:[t1,t2,t3]}。此对象已通过“react redux”的“connect”功能映射到道具。 当我改变属性“显示”或“creative.name”时,它确实会触发重新渲染。但是如果我将t0追加到"creative.tags",它就不会运行re-渲染。 我必须分配一个新变量来

  • 问题内容: 我有一个动作和减速器,可以更新全局计数器。快速执行此操作。减速器为每个操作返回状态的新副本。减速器看起来像: 我在各种React组件上使用的方法。并非所有组件都关心此循环计数器。因为我在每个刻度上都在化简器中返回新状态,所以所有订阅的组件都将执行,这会导致不必要的React渲染调用。 这些组件之一如下所示: 即使此组件不依赖它,也会触发重新渲染。这会导致重新渲染,过度渲染,多次渲染,不

  • 我正在尝试学习React(使用redux),所以我正在制作一个应用程序,在其中我可以创建训练计划,将训练添加到计划中,然后将训练添加到训练中。 PlanListComponent 我的PlansList组件为每个计划呈现一张卡片。在这张卡片中,它为该计划中的每个训练呈现一个训练列表。将训练添加到计划后,“计划列表”组件不会重新渲染。添加的训练仅在我刷新页面后显示。我之所以选择这种情况,是因为我必须