Creating a Context Menu with React-Redux - javascript

We use Redux in large parts of our React application. One area where we struggle with is the context menu. Up to now it worked like this:
onRightClick -> createItems -> openMenu -> onItemClick: invoke callback and close menu
So we had a callback in each item when it is clicked. With Redux, that no longer works, because:
dispatch(actionCreator_openContextMenu(items))
... performs a store update. The Redux action returned by the action creator cannot have callbacks in it, because they are not serializable/jsonizable.
We furthermore need to perform asynchronous operations (i.e. server roundtrips) in many context menu click actions, so the click actions are not plain store updates.
The question is: how does this align with the Redux pattern and its constraints? How would one do this with Redux?
To clarify: this question is not about the UI side in react, it's about redux.

I actually wrote an article that covers this exact question: Creating Reusable Generic Modals in React and Redux. The approach I described in that article can be summarized as having the code that requests the dialog include a pre-made action object that gets passed to the dialog component as a prop, and the dialog can then dispatch that action (possibly with additional info attached) when it's closed.
A couple other options:
Have the dialog dispatch some "signal" action when it closes, and use sagas or observables to execute the additional async logic in response
There's an interesting-looking library called redux-promising-modals. I haven't used it yet myself, but it appears to have a prebuilt middleware and reducer for tracking a lost of open modals. The middleware returns a promise whenever you dispatch PUSH_MODAL_WINDOW, and will resolve the promise when you dispatch the corresponding POP_MODAL_WINDOW.

I think what you are looking for is a redux middleware that could handle async side effects. There are dozens of libraries out there that can help with this, but I would suggest your team looks into some of the following libraries that have great communities and are well documented:
Redux-Saga https://github.com/redux-saga/redux-saga (easy to understand and test)
Redux-Thunk https://github.com/gaearon/redux-thunk (extremely easy to understand, hard to test)
Redux-Observable https://redux-observable.js.org/ (you would need some previous knowledge on reactive programming, easier to test than redux-thunk)

Related

Question about Redux async operations with Thunk

I just recently got introduced to Redux and decided to learn how to implement it. At the moment I'm refactoring some of my previous studying-projects and implementing the global state logic provided by the tool.
The thing is, I've recently stumbled upon the thunk middleware for async actions and got curious about something that's probably a simple concept misunderstanding but that I just can't get over.
So, why would I dispatch an async action? I just can't see the benefits of doing that way instead of waiting for the execution of whatever I'm doing and just then dispatch the action carrying the data I want.
Using a simple fetch call as an example, why would I not do the following:
->await fetch data
->dispatch fetched data
And instead do this:
->dispatch action
->await dispatch action
There's probably some use cases that I don't know of because for me, a beginner, sounds like extra code for something that maybe didn't require it? Idk.
Could someone help me? =)
Yep, as you found, that's Dan Abramov's original explanation of why something like the thunk middleware exists.
I recently wrote a new Redux docs page on Writing Logic with Thunks, which goes into more detail on the purpose behind thunks and how to use them correctly. I'll quote from the "Why Use Thunks?" section:
Thunks allow us to write additional Redux-related logic separate from a UI layer. This logic can include side effects, such as async requests or generating random values, as well as logic that requires dispatching multiple actions or access to the Redux store state.
Redux reducers must not contain side effects, but real applications require logic that has side effects. Some of that may live inside components, but some may need to live outside the UI layer. Thunks (and other Redux middleware) give us a place to put those side effects.
It's common to have logic directly in components, such as making an async request in a click handler or a useEffect hook and then processing the results. However, it's often necessary to move as much of that logic as possible outside the UI layer. This may be done to improve testability of the logic, to keep the UI layer as thin and "presentational" as possible, or to improve code reuse and sharing.
In a sense, a thunk is a loophole where you can write any code that needs to interact with the Redux store, ahead of time, without needing to know which Redux store will be used. This keeps the logic from being bound to any specific Redux store instance and keeps it reusable.
The Redux FAQ entry on "why do we use middleware for side effects?" links to additional information on this topic.

Manage Data with React Components

I am trying to build a new react app and I have some question about the architecture.
I have 2 components:
Adress
CreditCard
Each Component has several inputs and api functions to get the data and also to update it.
When I use both components in one Page, how can I trigger an update for both components?
Page
Address
CreditCard
Submit Button
The Submit Button should trigger the Update function and wait until both are finished.
I tried to give a function from the Page to the child components via props, but I think this is the wrong way.
Redux
For complex interactions between different components you can use redux. Redux holds the state of your entire application and can only be updated with actions.
An action will trigger a reducer. A reducer returns a new version of the state with what ever update you set there.
Treat redux some what like a database, do not store things multiple times and keep a good separation of concerns. There's an awesome library that lets you aggregate and manipulate data called reselect.
Reselect
This library will let you take several parts of the store and combine them for your needs in any given scenario.
Conclusion
To conclude, these's libraries are part of a stack I've been using for about 2.5 years (reselect only 1 year). I've found them very powerful for handling complex data. That being said there are other options like graphql, apollo or relay.

What is the difference between a redux middleware and a redux-observable epic?

I would like to understand when it is appropriate to use a redux middleware over a redux-observable epic (and vice versa).
From the redux middleware documentation
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
From the redux-observable documentation
While you'll most commonly produce actions out in response to some action you received in, that's not actually a requirement! Once you're inside your Epic, use any Observable patterns you desire as long as anything output from the final, returned stream, is an action.
My understanding is that an action in a redux middleware may or may not hit a reducer and if it does, it may or may not result in a change of state. In an epic you can produce a new action which may or may not hit a reducer or result in a change of state.
It looks like both can be used to enable side effects so the difference between the two is becoming a bit blurry to me.
Question: Is the FRP foundation the only thing that sets them apart or are there specific events in the lifecycle of an application that are better dealt with a classic middleware or an epic?
"Middleware" are a general type of thing that can be used to customize a Redux store. redux-observable is a specific Redux middleware, which lets you use RxJS logic to interact with dispatched actions.

What is an idiomatic way of checking props (or state) before dispatching an action?

In one of my React components, I'm using componentWillMount() to call a function I passed in as a prop via react-redux. This function dispatches an action that redux-saga listens on to load search filters for a form.
Now that I'm using redux-persist and the state rehydrates automatically, I would like to check if these search filters exist and were hydrated before calling my function. There's not much point in dispatching an action to retrieve data that's already in state and ready to use.
What is an idiomatic way to do this? Should I just check the array length on each prop in an if statement and only call the function if they exist already? Or should I be leveraging redux-saga anyway?
Edit: Writing business logic inside the Action Creator seems like an anti-pattern, but it's an option. Also, writing custom Redux Middleware is also an option. Will investigate both and leave an answer if necessary.
Edit 2: I'm not going to answer my own question, because the solution I found doesn't strictly relate to this question. I discovered redux-logic and it's been perfect for my use case.

In "Reflux", what purpose do actions serve?

I'm familiarising myself with both Flux architecture, and Reflux - the simpler version, without a dispatcher - for use with ReactJS.
In full Flux, it sounds like actions have (or at least, can be made to have) a definite and non-trivial purpose: they can be used to update external services (eg. save data back to the server via an API), as described in this question: Should flux stores, or actions (or both) touch external services?
However, in Reflux, the actions are definitely just dumb message parsers. So my question is, what purpose do they serve? Why have them at all? What bad things would happen if your Views/Components just called methods on your store directly?
I'm about to convert my little app from Flux to Reflux, and it looks like I'll be moving all the logic currently in my actions over to the store. It seems to me like the actions in Reflux do nothing other than act as a useless middleman between the component and the store. What am I missing?
Besides the ability to listen for an action in any number of stores as pointed out in the OP comments:
Reflux actions can also touch APIs and such, by placing it in the preEmit action hook for example. Typically you'd create an async action, add some async stuff in the preEmit hook, and then call the "completed" or "failed" sub-actions when the async work is done (or has failed). You can also do sync work in the preEmit hook of course. Logging comes to mind.
It's also fully possible to listen to an action in a store and perform the async work in the store, then call .completed or .failed from there, but I think the consensus that has formed is that stores shouldn't do that work, stores should just react to changing data, not perform business logic.
Async actions also work as promises. Of course you could implement your stores to do that as well, but I'd argue that that's a lot of responsibilities for a data store.

Categories