Accessing react-router from flummox action/store

704 views Asked by At

I want to be able to make an API call in a Flummox action and transition differently depending on the response. I can pass the router into the action call but am looking for advice on a potentially better way.

UPDATE:

The correct answer is below but I wanted to add some detail to this.

I'm doing an isomorphic app that 1. needs to get data from an api and 2. may need to redirect based on the api response. Whatever I do needs to work through an express.js app and through react.

I made a small lib that does the api call and return some results. I pass it an object (query params object from express for the server-side or a similar object I create for the react-side). This lib makes the request, determines if a redirect is needed and passes back errors, path (string), redirect (boolean), and data (json).

In express, if the redirect boolean is true, I just redirect to it with the current query params. If it's false, I pass the data to flux through an action which updates a store. I then renderToString with react, serialize stores so the clint-side can bootstrap, and send a rendered page to the client.

In react, the redirect boolean isn't important, I get the response back from my lib, pass the data to my flux action, and just transition to whatever the path is. There's really no notion of redirection. Just go to the path no matter what.

Hopefully this is helpful to someone.

1

There are 1 answers

1
Anders Ekdahl On BEST ANSWER

In my setup I have my own router module which just wraps the instance of react-router that I create at startup. That makes it easy for any part of the application to just require that module and do what it needs to.

But I would advise you not to have side effects like a call to the router inside your actions. Actions should concern themselves on mutating your application state, and nothing more. It should be possible to call the same action from anywhere in your application which needs to perform the mutation that the action encapsulates.

So if you're switching routes during an action, you're basically tying that action to that particular use case. Let's take an example. You have a todo list, with an input box at the bottom to add a new todo. For that use case, it might be useful to switch route after you saved the todo. Perhaps you switch to Recent Todos or something. But then a new use case comes along where you want to be able to add new todos during another workflow, perhaps the user is planning her week and should be able to add todos on different days. You want the same action that adds a todo, but you certainly don't want to switch routes because the user is still planning the week.

I haven't used Flummox a lot, but from my understanding your Flux object returns whatever the action returns when you trigger an action. So instead of putting the route change inside your action, make sure to return the response from the action and let your component decide if the route should be changed. Something like this:

// todo-action.js
class TodoActions extends Actions {
  createMessage(todo) {
    return TodoStore.saveToServer(todo);
  }
}

// todo-list.js
const TodoList extends React.Component {
  render() {
    ...
  }
  addTodo(todo) {
    this.props.flux.addTodo(todo).then(response => {
      if (response.some.prop === someValue) {
        this.props.router.transitionTo(...);
      }
    });
  }
}

That way, the action is still nicely decoupled from the route change. If you want to do the route switch in more than one place, you could encapsulate that in a addTodoAndSwitchRoute method in your Flux class.