Reacting to changes in derived state with redux [closed] - redux

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 13 days ago.
Improve this question
I'm using redux at a pretty complicated project. It has a lot of complicated action creators, reducers and selectors. I need to trigger a certain action if some derived state, which is computed via selectors, changes.
The naive way of implementing it would be to go through all the action creators that could change it and insert triggers there. However, it's bad because it's a lot of repetitive code and it doesn't safeguard from adding some action in the future that can change that derived state without this trigger.
Previously, this was achieved via React useEffect which had all derived state as dependencies. It was a very clean and effective way of reacting to changes in state. However, now I need to move this logic to be redux-only.
What would be a good way to achieve this?

That sounds like an excellent use case for the Redux Toolkit "listener" middleware, which specifically has the ability to run reactive logic in response to both specific action types, and state-based conditions. A basic example
listenerMiddleware.startListening({
predicate: (action, currentState, previousState) => {
// Trigger logic whenever this field changes
return currentState.counter.value !== previousState.counter.value
},
effect: (action, listenerApi) => {
// run arbitrary sync or async logic here,
// including dispatching actions, reading state, and much more
}
})
See the Redux docs and these articles for more details:
Redux docs: Using Redux > Side Effects Approaches
RTK docs: createListenerMiddleware API reference
Idiomatic Redux: Designing the RTK Listener Middleware
Reactathon 2022: The Evolution of Redux Async Logic

Related

Vuex best practices for working with additional classes: import into view or only in the Store? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I am building an application and am not sure how to phrase this question in a way that would help me find anything on Google.
My question is: When using a Vuex store along with some additional classes, is it best practice for the view components to access those classes directly or should they only be accessed through the store?
More detail: Currently, my project has a Vuex store with modules (userModule manages the current logged-in user, uiModule manages certain user-interface elements' visibility and content, etc).
I also have some services. AuthService contains the methods for communicating with Firebase's Auth, DatabaseService contains Firestore read/write methods.
I import the services into the Vuex store modules that require them, and access them as needed through the Store. Reading over my code, in some cases I have accessed the services directly from the view - for instance, Login.vue imports AuthService and accesses it directly. like so:
import authService from '../services/auth.service';
export default {
...
computed() {
authService() { return authService }
}
...
}
<button>{{authService.auth.currentUser() ? 'log out' : 'log in'}}</button>
I think overall it would be better to use the Store, as it would reduce the number of times I import the same object - though I'm not sure how much of a concern it is to import the same object multiple times. Confirmation and discussion are appreciated.
Thanks!
There's no penalty for importing the same module multiple times throughout your project, the top-level code in that module will only be executed once.
I don't think there's a right or wrong answer to your question (it may get closed for being "opinion-based").
Every time you import a module, it becomes a direct dependency of the importing module. This may make unit testing more difficult – how can you cleanly mock the imported module? (Certainly there are ways to do this, I'm just playing devil's advocate.)
When you expose the service class directly on the component instance like you have, then the service class becomes dependent on Vue now because the data properties it exposes need to be reactive for it to be used within the template like that. Vue will make all the properties on the class reactive now. The class implementation also needs to be aware that this will happen and it must comply with Vue's reactivity limitations when it mutates its own data.
For something simple like getting the current user, to me that seems more appropriate to store in Vuex instead of requiring every module import auth.service.
Try to maintain only a single "source of truth", don't share the ownership of data around because it becomes difficult to maintain.

How can I subscribe to changes in a redux store within an actions file

I have the following code
const reduxStore = require('redux/store');
console.log(typeof reduxStore.subscribe);
If I run that in a redux actions file my typeof is undefined.
If I run it in a vanilla js my typeof is function.
Now maybe doing this seems counterintuitive but I have a pattern where I have a shared actions file, that is to say the actions defined in this file can be used in two different reducers.
However some of these actions while shared between reducers (reducer1, reducer2) must cause actions to run that are individual to the particular store domain.
So dependant on what happens when reducer1.acceptGeoCode runs in the part of the application using reducer2 then reducer2.geoCodeSuccess should be run or reducer2.geoCodeFailed
it seems easiest to me to subscribe to changes in my reducer2 actions js, and then on the changes dispatch the local action I should use.
So that is why I want to use reduxStore.subscribe within an actions file. How do I do that, or failing that what is the proper way to do what I want to do which I feel must be doable.
If I understand you correctly, you want to have reducer 2 be aware of how reducer1 handled an action, is that right?
The way to do that is by composing reducers (as opposed to combining them). See this in action here: Stack Overflow
A couple of other points that might help you on your way:
Reducers should be pure. This means we don't do ajax calls (or other side effects) from inside a reducer. That is the domain of actions (ex: redux-thunk) and middlewares.
In the majority of applications, there should really only be one store. So, if you have a pattern where you have one store subscribing to another, then you should probably refactor your code to have just one store. Just to be clear, you can have several reducers combined (or composed) together in a single store - that's how Redux is designed to work.

With React / Redux, is there any reason not to program the store globally?

I love Redux, but to use it, I have LOTS of additional code scattered all over my application: connect, mapDispatchToProps, mapStateToProps etc etc
It appears to me however that I should be able to both dispatch to the store and get any value from the store via a global window level reference to the store object. If I did this, it would cut alot of code out of my application.
So the question is, what is wrong with this approach? Why NOT do all my Redux disptach and state access via window.store?
I wrote a long Reddit comment a while back about why you should use the React-Redux library instead of writing store code by hand.
Quoting the main part of that answer:
First, while you can manually write the code to subscribe to the Redux store in your React components, there's absolutely no reason to write that code yourself. The wrapper components generated by React-Redux's connect function already have that store subscription logic taken care of for you.
Second, connect does a lot of work to ensure that your actual components only re-render when they actually need to. That includes lots of memoization work, and comparisons against the props from the parent component and the values returned by your mapStateToProps function for that component. By not using connect, you're giving up all those performance improvements, and your components will be unnecessarily re-rendering all the time.
Third, by only connecting your top-level component, you are also causing the rest of your app to re-render unnecessarily. The best performance pattern is to connect lots of components in your app, with each connected component only extracting the pieces of data it actually needs via mapStateToProps. That way, if any other data changes, that component won't re-render.
Fourth, you're manually importing the store into your components, and directly coupling them together, thus making it harder to test the components. I personally try to keep my components "unaware" of Redux. They never reference props.dispatch, but rather call pre-bound action creators like this.props.someFunction(). The component doesn't "know" that it's a Redux action creator - that function could be a callback from a parent component, a bound-up Redux action creator, or a mock function in a test, thus making the component more reusable and testable.
And finally, the vast majority of apps built using React and Redux use the React-Redux library. It's the official way to bind the two together, and doing anything else will just confuse other developers looking at your project.
Also, per the Redux FAQ entry on importing the store directly:
While you can reference your store instance by importing it directly, this is not a recommended pattern in Redux. If you create a store instance and export it from a module, it will become a singleton. This means it will be harder to isolate a Redux app as a component of a larger app, if this is ever necessary, or to enable server rendering, because on the server you want to create separate store instances for every request.
Summarizing all that:
Better performance
Lower coupling via dependency injection of the store
Better testability
Better architecture
I'd also suggest you read through my two-part post The Tao of Redux, Part 1 - Implementation and Intent, and The Tao of Redux, Part 2 - Practice and Philosophy. These two posts discuss the history and intent behind Redux's design, how it's meant to be used, why common usage patterns exist, and other ways that people may use Redux.

Apollo: Call a mutation server-side from cron job? [duplicate]

This question already has answers here:
Apollo GraphQL: Call a Mutation from the Server?
(2 answers)
Closed 2 years ago.
I have a Meteor app that uses Apollo and I am using SyncedCron (https://github.com/percolatestudio/meteor-synced-cron) to schedule an update operation on the database every 2 hours.
Every two hours, fetch X data from some external API and store in Y collection of the database. Rinse and repeat.
My question is this: should this update operation be implemented as a graphQL mutation, and called server-side from within the cron job (if so, how do you do it?!), or should this be implemented as a normal JS function since it will only ever execute on the server?
All the mutation examples I can find online are invoked from the client by wrapping your View component in a graphql-enabled HOC.
Perhaps I am just misunderstanding the scope of mutations, and the larger question here is whether or not mutations CAN be invoked from the server, or if they are client-side only.
Hoping to find some clarification here on mutation best practices. Thanks!
I think you would just use axios (http call) or a meteor method here. I think mutations are just for browser-to-server.

Redux - dispatch actions which happen frequently and bypass the store ?

I'm building a synthesizer which has a piano-style keyboard UI input.
The keyboard note on/off events can happen quite frequently, these are used to update different parts of the UI and to trigger audio.
What is the frequency threshold which Redux can handle events? For example, if an event occurs 60 times per second which needs to update some aspect of the UI, how would one handle that using Redux patterns ?
I'm fine with doing this event-ing outside of Redux store entirely if Redux doesn't handle this use case.
Redux doesn't have any magic built into it, it's just an immutable state handler, so whatever javascript can do, redux can do.
What you want to take care of are dom operations, and in your case I'm assuming sound operations.
so your optimizations would be more on the react side, not redux.
if you want help with that, share your relevant react code here.
In general, the place to start optimizing react is shouldComponentUpdate
EDIT:
Here are some links I've found that might give some guidance / inspiration:
https://github.com/xjamundx/react-piano
https://github.com/DanielDeychakiwsky/react-piano

Resources