user5407287 user5407287 - 4 months ago 64
React JSX Question

Clear Redux Store

I have a web socket that accepts an object called PushMessage and sends it to a React page, which subsequently updates in real-time. The way this works is that the user searches for the PushMessage he wishes to display, and this is then passed in. However, what happens right now is that if the user searches for the first PushMessage, that one is displayed, but if he or she then searches for another PushMessage, both of them are displayed. I would like to only display the second of them. In order to do this I feel like I need to clear the Redux store (return it to its initial, empty state). However, I can't figure out how to do this.

My Reducer is given by:

var Redux = require('redux');
var _ = require('lodash');

var pushNotificationDefaultState = {};


var pushMessageReducer = function(state, action) {
switch(action.type) {
case 'RECEIVED_PUSH_MESSAGE':
var obj = JSON.parse(action.PushMessage);
return _.assign({}, state, obj);
default:
if (typeof state === 'undefined') {
return pushNotificationDefaultState;
}

return state;
}
};

module.exports = Redux.combineReducers({
pushMessages: pushMessageReducer
});


In the component I have:

function mapStateToProps(state) {
return state;
}


var AppContainer = connect(
mapStateToProps,
null
)(App);


Any and all help would be appreciate. Thanks in advance.

Answer

You can achieve this in a number of ways, I will show you how I would approach it. Let's look at your state right off the bat - because you are using combine reducers you are splitting your state like so :

{
  pushMessages: { pushMessages state in here }
}

So combineReducers is great when you want to split your app into kind of "substates", thought redux is still single store in this instance. Right now you just have the single substate of pushMessages.

I would take the component and set up an action to add a message to it (and maybe one to remove message eventually). I am using immutable.js because I happen to like working with it and IMO it makes redux nice to work with because the state should be immutable anyways (again, personal opinion).

So here are your reducers :

 var pushMessageReducer = function(state = immutable.Map(), action) {
    if (action && action.type) {
        switch (action.type) {

            case actions. RECEIVED_PUSH_MESSAGE:
                return state.update('messages', immutable.List(),
                    (oldMessages) => oldMessages.push(action.PushMessage)
                );


            default:
                return state;
        }
    }
    return state;
}

So what this does is set your state up like so :

{
   pushMessages: {
      messages: [ ... all your messages pushed in here] 
   }
}

Because you are using combine reducers your container should be subscribed to it's substate of pushMessages, so in your component you will have this.props.messages with an array of your messages. (if you have not subscribed to the sub state its just this.props.pushMessages.messages. And to display the last item all you really need is something like this (this is using lodash, you can certainly do this in vanilla js or whatever you want)

 constructor(props) {
    super(props);
    this.getLastMessage = this.getLastMessage.bind(this);
 }     

  getLastMessage() {
      return _.last(this.props.messages);
  }

  render() {

     return(
         <div>
           Last Message : {this.getLastMessage())
         </div>
     );
  }

So maybe you don't want the list to contain everything and only show the last one (I'm not sure what exact business logic you are looking for) but you can easily add an REMOVE_PUSH_MESSAGE action and just pop or splice from that array of messages. (and then you could just show this.props.message without the _.last). Hope this helps!

Edit:

Here is how I would set up your container:

import immutable from 'immutable';
import { connect } from 'react-redux';
import Component from './component';
import * as actionCreators from './action-creators';

function mapStateToProps(state) {
    const normalizedState = state.get('pushMessageReducer', immutable.Map()).toJS();

    return {
        messages: normalizedState.messages
    };
}

function mapDispatchToProps(dispatch, ownProps) {
    return {
        myAction: actionCreators.myAction.bind(null, dispatch)
    };
}


export default function(component = Component) {
    return connect(mapStateToProps, mapDispatchToProps)(component);
}

You'll notice the normalizedState in mapStateToProps, I use this to grab the section of the state I want to use in this container, unless your app only has 1 smart component then you probably wouldn't do this. It just grabs the part of the state (from immutable) that I am using in this container, in your case it's pushMessages. So now in this component you connected, you should have this.props.messages with your items. I also use mapDispatchToProps to bind in my actions, because it gives you dispatch in your action creators which makes async really easy.

With the combined code properly hooked up (I didn't know hooking up the action here), you should fire that RECEIVED_PUSH_MESSAGE action creator with a new message on action.PushMessage. This then connects to your mapStateToProps which updates this.props.messages on your component, which should only be rendering the last item in the list.

Comments