最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to listen to redux action stream in component - Stack Overflow

programmeradmin4浏览0评论

I'm working on a React application that uses the following architecture:

  • redux
  • typesafe-actions
  • redux-observable

My question is: How can I execute an UI action on specific redux action?

For example, suppose we have the following async actions defined with typesafe-actions:

export const listTodo = createAsyncAction(
  'TODO:LIST:REQUEST',
  'TODO:LIST:SUCCESS',
  'TODO:LIST:FAILURE',
)<void, Todo[], Error>();

An Epic will watch for listTodo.request() and send the API call, then convert the response to a listTodo.success() action. Then the redux reducer will be triggered by listTodo.success() action and store the todo list into redux store.

In this setting, suppose I want to do the following things in an ponent:

  • dispatch a listTodo.request() action to retrieve all the actions
  • After the async request is done (i.e. after listTodo.success() action appears in the action stream), redirect the UI to a second path

So my question is, how could I watch the action stream and react to the listTodo.success() action?

UPDATE: To avoid being too specific, we can think of another case. I want to simply display an alert with window.alert() after listTodo.success() appears in the action stream. Or simply console.log(), or whatever that changes local state (instead of global redux state). Is there a way to implement that?

UPDATE 2: There is a similar question here, but for Angular w/ ngrx. What I want to do is exactly the thing described in above post, but in React / redux-observable fashion:

import { Actions } from '@ngrx/effects';

@Component(...)
class SomeComponent implements OnDestroy {
    constructor(updates$: Actions) {
        updates$
            .ofType(PostActions.SAVE_POST_SUCCESS)
            .takeUntil(this.destroyed$)
            .do(() => /* hooray, success, show notification alert ect..             
            .subscribe();
    }

}

I'm working on a React application that uses the following architecture:

  • redux
  • typesafe-actions
  • redux-observable

My question is: How can I execute an UI action on specific redux action?

For example, suppose we have the following async actions defined with typesafe-actions:

export const listTodo = createAsyncAction(
  'TODO:LIST:REQUEST',
  'TODO:LIST:SUCCESS',
  'TODO:LIST:FAILURE',
)<void, Todo[], Error>();

An Epic will watch for listTodo.request() and send the API call, then convert the response to a listTodo.success() action. Then the redux reducer will be triggered by listTodo.success() action and store the todo list into redux store.

In this setting, suppose I want to do the following things in an ponent:

  • dispatch a listTodo.request() action to retrieve all the actions
  • After the async request is done (i.e. after listTodo.success() action appears in the action stream), redirect the UI to a second path

So my question is, how could I watch the action stream and react to the listTodo.success() action?

UPDATE: To avoid being too specific, we can think of another case. I want to simply display an alert with window.alert() after listTodo.success() appears in the action stream. Or simply console.log(), or whatever that changes local state (instead of global redux state). Is there a way to implement that?

UPDATE 2: There is a similar question here, but for Angular w/ ngrx. What I want to do is exactly the thing described in above post, but in React / redux-observable fashion:

import { Actions } from '@ngrx/effects';

@Component(...)
class SomeComponent implements OnDestroy {
    constructor(updates$: Actions) {
        updates$
            .ofType(PostActions.SAVE_POST_SUCCESS)
            .takeUntil(this.destroyed$)
            .do(() => /* hooray, success, show notification alert ect..             
            .subscribe();
    }

}
Share Improve this question edited Mar 27, 2019 at 19:10 charlee asked Mar 27, 2019 at 18:55 charleecharlee 1,3691 gold badge12 silver badges22 bronze badges 7
  • How do you do navigation in your app? Are you using a redux based router like connected-react-router ? – Harald Gliebe Commented Mar 27, 2019 at 19:02
  • @Harald I don't want this question to be too specific. I know if the route is stored as redux state this problem can be solved. What if, say, I want to simply show a dialog with window.alert() after listTodo.success() is observed? – charlee Commented Mar 27, 2019 at 19:05
  • Then either create a new epic that watches for listTodo.success(), perform a side effect with action$.tap(() => {window.alert()}) and then ignoreElements() – Harald Gliebe Commented Mar 27, 2019 at 19:10
  • Thanks @Harald. Can I do this (create an epic) in a ponent? – charlee Commented Mar 27, 2019 at 19:11
  • You need to use bineEpics() to bine all the Epics in your application and run it with the epicMiddleware. See redux-observable.js/docs/basics/SettingUpTheMiddleware.html how to set up redux-observable correctly – Harald Gliebe Commented Mar 27, 2019 at 19:14
 |  Show 2 more ments

4 Answers 4

Reset to default 1

With redux the ponents update based on state.

If you want to update a ponent based on an action than you update the state in the reducer, such as setting {...state, success: true} in the reducer. From there you simply read the state into your ponent as you normally would and if the state is changing to success than you show your window.

I feel like a dialogue should be a side effect, so you'd put them in epics

Nowadays, the best way to listen for actions inside a ponent is using the createListenerMiddleware that is included with the redux-toolkit (RTK), bined with useEffect():

useEffect(() => {
  // Could also just `return dispatch(addListener())` directly, but showing this
  // as a separate variable to be clear on what's happening
  const unsubscribe = dispatch(
    addListener({
      actionCreator: todoAdded,
      effect: (action, listenerApi) => {
        // do some useful logic here
      },
    })
  )
  return unsubscribe
}, [])

Docs: https://redux-toolkit.js/api/createListenerMiddleware#adding-listeners-inside-ponents

I usually use Epic Observables for side effects, and use a selector for state changes in ponents, but there are certain situations where listening for an action directly inside a ponent (instead of a state change) is the best solution. The above fits that bill perfectly.

Might be a little late but I solved a similar problem by creating a little npm module. It allows you to subscribe to and listen for redux actions and executes the provided callback function as soon as the state change is plete. Usage is as follows. In your ponentWillMount or ponentDidMount hook:

 subscribeToWatcher(this,[
      {  
        action:"SOME_ACTION",
        callback:()=>{
          console.log("Callback Working");
        },
        onStateChange:true
      },
    ]);

Detailed documentation can be found at https://www.npmjs./package/redux-action-watcher

发布评论

评论列表(0)

  1. 暂无评论