index
index

Reputation: 3727

Clear one redux state on page transition

I'm creating a notification state like this (in redux),

import { STORE_NOTIF, PURGE_NOTIF } from '../actions/notif';

const defaultState = {
  kind: null,
  message: null
}

export default function notifReducer(state = defaultState, action) {
  switch(action.type) {
  case STORE_NOTIF:
    return {kind: action.kind, message: action.message};
  case PURGE_NOTIF:
    return defaultState;
  default:
    return state;
  }
}

this works for events I know to control. But where should I implement the clearing (PURGE_NOTIF) for when I transition to pages, say from sign-in to home page? I don't want to write a componentWillMount (and I don't think that's the write way) on every component to clear the notifState. Should this be like somewhere in the routes? I use react-router BTW.

UPDATE with answer

My new reducer looks like this where I added a displayed boolean

import _ from 'lodash';

import { STORE_NOTIF, PURGE_NOTIF, DISPLAY_NOTIF } from '../actions/notif';

const defaultState = {
  kind: null,
  message: null,
  displayed: true
}

export default function notifReducer(state = defaultState, action) {
  switch(action.type) {
  case STORE_NOTIF:
    return _.merge({}, state, { kind: action.kind, message: action.message, displayed: action.displayImmediately });
  case DISPLAY_NOTIF:
    return _.merge({}, state, { displayed: true });
  case PURGE_NOTIF:
    return defaultState;
  default:
    return state;
  }
}

and in my client is where I check if it's been displayed already or not and handle appropriately.

const scrollTop = () => { window.scrollTo(0, 0) }
const handleNotifs = (store) => {
  const notifState = store.getState().notifState;

  if (notifState.message) {
    if (notifState.displayed) {
      store.dispatch({type: PURGE_NOTIF});
    } else {
      store.dispatch({type: DISPLAY_NOTIF});
    }
  }
}

const store = applyMiddleware(...middlewares)(createStore)(reducer, initialState);

ReactDOM.render(
  <Provider store={store}>
    <Router onUpdate={() => {scrollTop(); handleNotifs(store)}} routes={routes} history={browserHistory} />
  </Provider>,
  document.getElementById('app')
);

Upvotes: 3

Views: 6700

Answers (1)

Florent
Florent

Reputation: 12420

If you define your React Router routes using plain route objects, you can define lifecycle events on your route. The simplest way to achieve what you described is to specify onLeave on the route.

const onLeave = () => store.dispatch({type: "PURGE_NOTIF"})
const routes = (
  {path: "/login", component: LoginPage, onLeave}
)

You need to pass a reference to store to your routes. Here is a possible solution:

// index.js
const store = createStore(/* ... */)
const routes = createRoutes(store)

ReactDOM.render(
  <Provider store={store}>
    <Router routes={routes} />
  </Provider>
)

// createRoutes.js
export default store => {
  const purge = () => store.dispatch({type: "PURGE_NOTIF"})

  return (
    {path: "/", component: Application, childRoutes: [
      {path: "login", component: LoginPage, onLeave: purge},
      {path: "dashboard", component: Dashboard},
    ]}
  )
}

Upvotes: 2

Related Questions