1

This is a topic that has been covered before, but I am still haven't quite found an answer I like and would love some advice.

I am having the following issue. My app contains an action called CREATE_RESPONSE, which creates a new response record and pushes it into the responses state. The action creator for this action is dispatched from my component when a user clicks a button.

onClick={() => { this.props.createResponse(); }} 

Now, after the user does this, I would like to open a modal for this new response. This modal relies on the new response state change, so must happen after createResponse.

The most intuitive solution for me would be to use a callback, but I believe this represents a Redux anti-pattern.

The other way would be to listen to response state changes, and then dispatch an action whenever the number of responses has changed (something similar to the subscribe example: http://redux.js.org/docs/api/Store.html#subscribe)

function responses(state) { return state.responses.size } let currentValue function handleChange() { let previousValue = currentValue currentValue = responses(store.getState()) if (previousValue !== currentValue) { // Dispatch action here } } store.subscribe(handleChange) 

The issue here is we are responding to all state changes that fulfill this condition. In my app, this incorrectly gets triggered on page load.

So my question boils down to: what is the best way to dispatch an action in response to a state change?

EDIT

Here are simplified versions of my Modal and Response reducers, respectively:

Modal

const modalState = Immutable.Map({ isOpen: false, view: null, modalProps: {} }); export const modal = (state = modalState, action) => { switch (action.type) { ... } } 

Responses

const responseRecord = Immutable.Record({ id: null, ... }); export const responses = (state = Immutable.List([]), action) => { switch (action.type) { case 'CREATE_RESPONSE': newResponse = new responseRecord(...); state = state.unshift(newResponse); return state; ... 
3
  • Why can't you just handle the modal in the reducer after you have handled the state changes for createResponse? Commented Mar 22, 2017 at 14:30
  • Hmm, how exactly would that work? Currently I have 2 reducers, one for Response and one for Modal. Each reducer only handles their own state. If you are saying to handle the modal state from the Response reducer, how exactly would I do that? I will update my question with the two reducers Commented Mar 22, 2017 at 14:41
  • I think your modal component should listen for the response state and open itself when the state changes. Commented Mar 22, 2017 at 14:49

1 Answer 1

1

You can have a case for CREATE_RESPONSE in your Modal reducer. Every action gets run through every reducer. Most of the time, it quickly falls through to the default. But if you want you can listen for the CREATE_RESPONSE and set isOpen to true.

Though I don't think that's necessary, either. Instead of an isOpen flag, you can add newRecord to the global state. Define the Modal as:

<Modal show={this.props.newRecord}... 

and clear newRecord in whatever action the Modal dispatches on being closed. It might be necessary to listen to that action in the responses reducer, but that is legal.

(I'm playing a bit fast-and-loose, since newRecord isn't a boolean. It should work, though you can also force it to boolean-ness as !!newRecord, or check directly for nullity)

This should solve the problem of having it open on page load. The Modal does exactly what it's supposed to do: be open whenever there is a new record, without any explicit command to do so. You just let React manage its visibility.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.