Brett
Brett

Reputation: 2746

redux-sagas callback (aka sagas and setState)

I want to set form loading state (spinner icon, disable input) when the user submits the form, and clear that state when the action completes or fails. Currently I am storing this state in my store, which involves creating an action creator and reducer, which is annoying for a few reasons:

  1. It's a lot more work than simply calling this.setState
  2. It's more difficult to reason about
  3. I don't really want to store local component state in my store

Essentially I want to do this within my form component:

handleFormSubmitted() {
  this.setState({ isSaving: true })
  this.props.dispatchSaveForm({ formData: this.props.formData })
    .finally(() => this.setState({ isSaving: false }))
}

Upvotes: 0

Views: 1718

Answers (1)

Josep
Josep

Reputation: 13071

You can't do that with redux-saga. What you are trying to do there goes against the basic principles of redux-saga.

redux-saga aims to be reactive by treating actions like events that describe what's happening in your app... So that other sagas (usually "watchers" using take) or the rootReducer can subscribe to those actions/events and do what they need to do...

Because of that redux-saga -unlike redux-thunk and redux-promise- doesn't change the behaviour of the dispatch method... So, with redux saga when you dispatch, you dispatch, and the reducers and the sagas are subscribed to the dispatched actions. But the dispatch method won't return a promise like it happens when you use other middlewares/store-enhancers.

So, the only way that redux-saga has to let the rest of the app know that the request of your form has finished is by dispatching an action (using the put effect) whenever that request finishes or errors, right? So, how could you possibly know directly from inside the component if a specific action has been dispatched?

Unless you make your own middleware (or you use a separate one) with a connector component: there is no way for you to subscribe to concrete actions inside a component.

Sure, you could access the context directly in order to get a hold of your redux store, and then you could use the redux subscribe method directly, but the listener function won't tell you what's the action that got dispatched. It will just get invoked when an action (any action) gets dispatched... maybe you could check if some property of the state has changed, but that's insane. So, unless you want to go down that route, which is crazy: you can't do that using redux-saga.

If you wanted to do something like that (which IMHO is not a very good idea) you would have to do it without using redux-saga. A possible way to do it could be something along the lines of:

handleFormSubmitted() {
  this.setState({ isSaving: true })
  yourFetchCall({ formData: this.props.formData })
    .then(payload => this.props.dispatchFormSaved(payload))
    .catch(error => this.props.dispatchSavingFormErrored(error))
    .finally(() => this.setState({ isSaving: false }))
}

Upvotes: 6

Related Questions