redux reducer not re-rendering components
Clash Royale CLAN TAG#URR8PPP
redux reducer not re-rendering components
Context: I am trying to make a web client that uses react redux and socket.io. The design is inspired by whatsapp and is honestly just a fun little side project I am using to learn react and redux.
The main issue is I have a ActiveChat component that does not re-render upon the store changing and recognizing the change . Redux Devtools even shows the diff and change in state.
The component has been connected:
//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;
I had the idea that I may somehow not be keeping the state pure as this is my first tango with state immutability in javascript and was hoping i'd receive help for the commmunity
The code is available here : https://github.com/YourFavouriteOreo/ChatClient ( Feedback is ALWAYS welcome as I am trying to get better at javascript )
The code snippet in question specifically is :
# 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
I have currently hotfixed this by setting state right after the action but this is not ideal as once I'll be using sockets , setState being async could lead to certain issues.
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();
;
Edit: This was asked so I will add it here . The return ...state,chats
does in-fact get result into return ...state, chats:chats
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)
EDIT 3 :
// render function for activeChat component
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
)
updateActiveChat()
And show the
render()
(or maybe a simplified version) from your component. Also provide evidence that your component is not rendered as you expect.– Code-Apprentice
Aug 12 at 5:24
render()
I have added all the git code in the project information . Action is available here : github.com/YourFavouriteOreo/ChatClient/blob/master/frontend/… ActiveChat Component here: github.com/YourFavouriteOreo/ChatClient/blob/master/frontend/…
– YourfavOreo
Aug 12 at 5:26
The links are great, but in case they ever become invalid, it helps to show your complete code here. (Note: "Complete" means enough to reproduce the behavior you are asking about. "Complete" does NOT mean all of the code in your app.)
– Code-Apprentice
Aug 12 at 5:27
In this particular case, it will also help to see your render() method in your question here as well as any other parts of your component class that are relevant.
– Code-Apprentice
Aug 12 at 5:28
1 Answer
1
I managed to fix it by executing concat differently in the reducer. I don't understand how this changed the end result since the object still changes but this seemed to fix .
Instead of :
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
I did:
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
EDIT: It turns out that Object.assign() does a shallow clone, this means that nested objects are references rather than copies . If you want to do a deepClone . You can use cloneDeep from lodash, I realized this with other problems I ended up getting later with other functions .
The new case handler is as follows in my solution.
_ is my import for 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
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Please show the
updateActiveChat()
action creator.– Code-Apprentice
Aug 12 at 5:21