I'm seeing a lot of "Reducer may not dispatch actions" in my error logs. We have a large redux/redux-thunk app. I've looked through our reducers, and none of them have dispatches in them. They are all synchronous functions that just return new state. No side effects. We do however dispatch actions with redux-thunk, and the errors we have seem to indicate that we only hit this error when dispatching new actions in a thunk.
I've found these two github threads, which I believe are related, but it appears to largely be a big back and forth with no resolution.
https://github.com/reduxjs/redux-thunk/issues/122
https://github.com/reduxjs/redux/issues/2753
"redux": "3.7.2",
"redux-thunk": "2.2.0",
I'd like to know, how I can fix this issue, or at least how I can gather more data on this. Most of the error stacks I have are largely from our last middleware calling next(action);. From our error logs I've only found instances of this issue with thunks.
Related
I am working on a WebSocket application that uses React/Redux stack with Sage as the side-effects handler. Saga dispatches events on incoming WebSocket messages and specific slice reducers either
1. Handle the message and update the state
2. Reply to Websocket message immediately - based on the current state
3. Raise an error - Invalid message
I would like to contain the business logic in reducers, hence would like the reducers to raise WebSocket send events or set an error state, rather than splitting these 2 to Saga handler. Strategy I am looking at is to have global states state.outgoingMessages and state.errors where any slice reducer can set these states. If an outgoingMessage is set the sage middleware would on resumption would write back to the WebSocket, if an error state is set an Error Component would render this.
I don't think I am violating any reducer/saga rules, however I have the dilemma of passing down a common state to reducers. There being quite a bit of discussion around this topic
https://redux.js.org/docs/recipes/reducers/BeyondCombineReducers.html#sharing-data-between-slice-reducers
provides a recipe of passing down additional sate. I can have a higher order reducer and pass down additional states outgoingMessages and error to slice reducers, would this be an anit-pattern, or is there a better way to handle the problem altogether?
I'm a little confused with Resolvers for routes. The problem that Resolvers solve for me is that an object is present in the component at rendering time. If I do it without Resolvers and start fetching objects in a component's constructor via Promise, accessing its nested properties in the template like
{{myObj.foo.bar}}
could lead to an error if the Promise does not resolve early enough, which is very likely when a http request needs to be done. However, the little info about receiving resolved objects from a Resolver tells me to do it like this in the component's constructor
this.route.data.subscribe(val => {...});
Isn't this the same sh*t as before? Ok, I admit, that the backend request has already finished, and I'll receive the subscription in no time. Nevertheless, I access the resolved data asynchronously again. There may be a very high chance that {{myObj.foo.bar}} is accessible at template rendering, but there is no guarantee, isn't it?
I don't know if I see that too critical. It's a gut feeling that using canActivate for the route and setting the resolved object to a Service that, in turn, can be accessed by any component synchronously comes closer to my intention, though.
Looking forward to clarifications
Wrap the whole template or parts where you need to access myObj with *ngIf:
<ng-container *ngIf="myObj?.foo">
{{myObj.foo.bar}}
</ng-container>
I'm building an library with Redux that involves using a timer. I have an action creator that dispatches a START_TIMER event and should also should also call start on a timer object. The code looks like this:
// thunk action creator
const startTimer = () => (dispatch, getState) => {
if (!getState().timer.isRunning)
externalTimerObject.start()
dispatch({
type: 'START_TIMER'
})
}
There are two issues I'm trying to solve:
If I want to log my actions to a database or localStorage so that I can replay them to get to a consistent app state then even if rootState.timer.isRunning is true, my timer object will not be running.
The conditional if (!getState().timer.isRunning) requires that I know where in the root state timer is mounted. Since I'm building this as a library, I can't assume that timer is always going to be mounted directly onto the root state.
If I want to log my actions to a database or localStorage so that I can replay them to get to a consistent app state then even if rootState.timer.isRunning is true, my timer object will not be running.
I think that this is actually correct by design. When you reproduce a recorded log, you want everything to happen exactly as it happened before in terms of the produced actions.
For example, rather than fire off the real AJAX requests from your computer, while replaying actions, you’ll probably want to replay the recorded AJAX responses that were dispatched during that user session in the past.
I think timer falls into the same category: from the Redux point of view, action history describes what happened “as a result” of side effects, and replaying the actions should be enough to get your app into the same state even if those side effects did not actually fire again.
The conditional if (!getState().timer.isRunning) requires that I know where in the root state timer is mounted. Since I'm building this as a library, I can't assume that timer is always going to be mounted directly onto the root state.
If you’re building a library, you also probably shouldn’t depend on the thunk middleware being available. It seems like you depend on it in your action creator. It is hard to say more without understanding your exact use case.
BookSleeve is very good in performance because it use async IO as much as could.
But the problem is, it may throw fatal exception from asynchronous operation and crash my application.
I know that keyword await can help, but I can't use await for every call.
Is there a way to catch the unhandled exception globally?
What version of the library are you using? BookSleeve internally observes its own exceptions specifically so that they should not cause any crashes, however, you can also:
handle the .Error event
handle the TaskScheduler.UnobservedTaskException event
strictly, neither of these should be required. It is the latter than would prevent app closures, but again: this should not matter - unless there is a bug in some of the code and it is missing one or more tasks
But on a more general level, it is good practice to check what happens to your tasks. If you don't want to await them, it would probably still be worth subscribing a ContinueWith which checks for exceptions. Also, you don't necessarily need to await; in many cases, connection.Wait(result) is fine too - although this does tie up a primary thread for a little longer (but note: it doesn't tie up the multiplexer).
I'm using the samples for the AwsFlowFramework, specifically helloworld and fileprocessing. I have followed all the setup instructions given here. All the client classes are successfully created with the aspect weaver. It all compiles and runs.
But trying to do .get on a Promise within an asynchronous method doesn't work. It waits forever and a result is never returned.
What am I doing wrong?
In particular the helloworld sample doesn't have any asynchronous method nor does it attempt to do a .get on a Promise. Therefore, it does work when copied outright and I can see in the activities client the "hello world" message printed. Yet, if I create a stub Asynchronous method to call get on the Promise<Void> returned by printHello, the client of the activities is never called and so the workflow waits forever. In fact the example works if I set the returned promise to a variable. The problem only arises if I try to call .get on the Promise. The fileprocessing example which does have asynchronous methods doesn't work.
I see the workflows and the activity types being registered in my aws console.
I'm using the Java SDK 1.4.1 and Eclipse Juno.
My list of unsuccessful attempts:
Tried it with Eclipse Indigo in case the aspect weaver does different things.
Made all asynchronous methods private as suggested by this question.
If I call .isReady() on the Promise this is always false even if I call it after I see the "helloworld" message printed (made certain by having a sleep in between). This leads me to think that Promise.get blocks the caller until Promise.isReady is true but because somehow this is never true, the client is not called and the workflow waits forever.
Tried different endpoints.
My very bad. I had a misconfiguration in the aop.xml file and so the load aspectj weaving for the remote calls was not correct.