redux reducer不重新渲染组件

时间:2018-08-12 03:28:34

标签: javascript reactjs redux

上下文:我正在尝试制作一个使用react redux和socket.io的Web客户端。该设计的灵感来自whatsapp,说实话,这只是我用来学习react和redux的一个有趣的小项目。

主要问题是我有一个ActiveChat组件,该组件不会在商店更改和识别更改后重新呈现。 Redux Devtools甚至显示差异和状态变化。

该组件已连接:

//Redux Mapping for Store and Actions
const mapStateToProps = state => {
  return { activeChat: state.activeChat };
};

const mapDispatchToProps = dispatch => {
  return {
    updateActiveChat: chat => dispatch(updateActiveChat(chat))
  }
}

const activeChatConnected = connect(mapStateToProps,mapDispatchToProps)(ActiveChat)


export default activeChatConnected;

我有一个想法,就是我可能不会以某种方式保持状态纯正,因为这是我的第一个探究javascript状态不变性的探戈,希望我能得到社区的帮助

代码可在此处获取:https://github.com/YourFavouriteOreo/ChatClient(欢迎反馈,因为我正努力提高javascript的能力)

有问题的代码段是:

# src/reducers
const rootReducer = (state = initialState,action) => {
      switch(action.type){
          case SELECT_ACTIVE:
          // Select Active Chat so as to display chat content
            var newActive = Object.assign(state.chats[action.payload.index])
            newActive["index"]= action.payload.index
            return {...state,activeChat:newActive}
          case UPDATE_CHAT:
          // Update store with new Chat Content
            var chats = Object.assign(state.chats)
            chats[state.activeChat.index].chatLogs.concat(action.payload)
            return {...state,chats}
          default:
          return state
      }
}

我目前已通过在操作后立即设置状态来修复此问题,但这并不理想,因为一旦我将使用套接字,则setState异步可能会导致某些问题。

inputHandler = logs => {
    // Handle Input from chatInput
    var newState = this.state.chatLogs;
    newState.push(logs);
    //Redux Action
    this.props.updateActiveChat(logs)
    console.log(this.state.chatLogs);
    // BAD HOTFIX
    this.setState({});
};

编辑:有人问过,所以我将其添加到这里。 return {...state,chats}实际上将结果获取为返回值{...state, chats:chats}

EDIT2:

// actions
import {SELECT_ACTIVE, UPDATE_CHAT} from "../constants/action-types"

export const selectActiveChat = selected => ({type: SELECT_ACTIVE, payload:selected})
export const updateActiveChat = chat => ({type: UPDATE_CHAT, payload:chat})

编辑3:

// activeChat组件的呈现功能

render() {
    if (this.state != null){
      return (
        <div className="column is-8 customColumn-right">
          <div className="topColumn">
            <h1 style={{fontFamily:"Quicksand,sans-serif", fontWeight:"bold", fontSize:"1.1rem"}}> {this.state.chatName} </h1>
            <p style={{fontFamily:"Roboto,sans-serif",marginLeft: "0.75rem",lineHeight:"1"}}> Chat Participants </p>
          </div>
          <ChatContent
            chatLogs={this.props.activeChat.chatLogs}
            isTyping={this.state.isTyping}
          />
          <ChatInput postSubmit={this.inputHandler} />
        </div>
      );
    }
    else {
      return <NoActiveChat/>
    }
  }
  componentWillReceiveProps(newProps){
// Change Props on Receive 
console.log("das new props");
this.setState({
  chatName: newProps.activeChat.chatName,
  chatLogs: newProps.activeChat.chatLogs,
  isTyping: newProps.activeChat.isTyping
})
}

1 个答案:

答案 0 :(得分:0)

我设法通过在reducer中不同地执行concat来修复它。我不明白这是如何改变最终结果的,因为对象仍然在改变,但这似乎可以解决。

而不是:

      case UPDATE_CHAT:
      // Update store with new Chat Content
        console.log("Update chat action executed");
        var chatState = Object.assign({},state)
        chatState.chats[state.activeChat.index].chatLogs.concat(action.payload)
        return {...chatState}

我做到了:

          case UPDATE_CHAT:
          // Update store with new Chat Content
            console.log("Update chat action executed");
            var chatState = Object.assign({},state)
            chatState.chats[state.activeChat.index].chatLogs = chatState.chats[state.activeChat.index].chatLogs.concat(action.payload)
            return {...chatState}

编辑:原来Object.assign()做一个浅表克隆,这意味着嵌套的对象是引用而不是副本。如果您想做一个deepClone。您可以使用lodash的cloneDeep,我意识到了其他问题,后来又遇到了其他功能。

新的案例处理程序如下所示。

_是我对lodash的导入

          case UPDATE_CHAT:
      // Update store with new Chat Content
      console.log("Update chat action executed");
        var chatState = _.cloneDeep(state)
        chatState.chats[state.activeChat.index].chatLogs = chatState.chats[state.activeChat.index].chatLogs.concat(action.payload)
        return {...chatState}