簡體   English   中英

我的Redux狀態發生了變化,React為什么不觸發重新渲染?

[英]My Redux state has changed, why doesn't React trigger a re-render?

我正在嘗試設計一個通知組件,其中通知將在某些場合出現(如連接問題,成功修改等)。

我需要通知幾秒后消失,所以我觸發狀態更改以從通知的componentDidMount setTimeout刪除Redux狀態的通知。

我可以看到狀態確實發生了變化,但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出於性能原因使用此方法。 循環一個大的狀態樹需要很長時間才能查看是否所有內容都相同。 當您保持樹不可變時 ,只需要進行===測試,並且過程變得更加容易。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM