I use the redux library in my application, i want to display an alert dialog in my widget according to certain conditions.
I have 3 different actions, in the middleware when one of these actions is requested, according to certain conditions i would like to display an alert dialog to notify my view with a message but i can't use my reducer to change my state with the message and notify a storeConnector because my dialog is a modal and not a Widget.
How can I do that ? I wanted to use Callback requested in my middleware instead of using my reducer. But because 3 actions can be used as output i can't use the action.callBack in my middleware.
You can listen to the Redux Store's stream directly without using a StoreConnector widget. You can do something like the following:
store.onChange.listen(() {
if (shouldShowModal()) {
showModal();
}
});
Related
I am designing an application in react/redux and I am new to flux/redux and unidirectional patterns. I ran into a problem which I am not sure how to properly solve within a unidirectional architecture
I want to illustrate the problem with the example of a user registration form that might show up in different parts of the app. Please note that the core problem is about if and where to handle subcomponent completion events and the UserRegistration is just an example.
Let's say I have a component UserRegistration which will render as a form. This component will handle its own submit action which may include some asynchronous calls to a server endpoint and in the end should lead to a modification of the store/state (e.g. adding new user data).
The user flow is the following:
user clicks on 'register' button
user sees registration form
user types in data and clicks 'submit'
user registration form disappears
I want to include this UserRegistration form in different places in the app.
Let's say I want to show the registration form based on a route /register and after succesfully registering I want to route back to /.
The intuitive thing for me to do (coming from a non-unidirectional world) would look something like this
function MyApp() {
const isRegisterRoute = //... somehow check if /register is active
return (
<button onClick={ () => { routeTo('/register') }}>register</button>
{
isRegisterRoute && (
<UserRegistration // handles actual registration internally (network calls and store modification)
onCompletion={ () => { routeTo('/' } } // pass completion handler which will route back to initial path
/>
)
}
)
}
This would solve the problem but I am wondering if having a callback for such a component with a complex flow is an anti pattern in a unidirectional architecture.
One concern is that the callback basically inverts the direction and it's no longer unidirectional.
Another concern is that I would have to pass the onCompletion handler down the chain within my component so it gets executed once the registration is complete. This passing around of the handler does not feel clean as it leaks into a lot of places.
On the other hand I don't want to handle the routing back to '/' inside the UserRegistration component as the success route or action might be different depending on where I use it so I want that logic to be decoupled from the component.
What would be the appropriate/best-practice solution for the problem described above within flux?
It's not data flow at all
It's not an anti-pattern as I don't see any data flow from sub-component to parent, like
<SubComponent onComplete={data=>this.setState({data})}/> // not good
reroute to another router is logic, the next router is the property passed to UserRegistration component, so it's the same as
<UserRegistration nextRouteOnComplete="/"/> // property
and handle routeTo logic in UserRegistration.
A function can be dynamic, do make sure no data will be passed to the callback function, the callback is designed to handle logics after complete, no data should be passed, and data update should follow the unidirectional data flow,
dispatch action -> reduce action -> mutate state -> rerender
Context: I want to create a modal which lets the user fill in a form, and submit it. The modal should close after the POST request finishes. There are multiple modals with similar behavior but different form content, so I need to make it reusable. The data in the form is not used anywhere else in the frontend app, and is only stored in the backend.
Relevant tech stack: react, redux, react-redux, redux-saga, no SSR
Option 1: Store modal & request state in redux
Opening and submitting the modal would trigger the following sequence of events:
Dispatch action to open modal
Dispatch action to submit form with data
Send POST request to submit form, set redux loading state to true
If success, set redux loading state to false, and "modal open" state to false
Concerns: Conceptually places a lot of functionality in redux, when that functionality is, in principle, specific to the modal itself.
Option 2: Store the request state in redux, but store modal state in the component, use useEffect to check when the request succeeds
Opening and submitting the modal would trigger the following sequence of events:
Open the modal, which changes some local "modalOpen" state to true
Dispatch action to submit form with data
Send POST request to submit form, set redux loading state to true
If success, set redux loading state to false
In the modal component, a useEffect hook or componentDidUpdate function checks if the state changed from e.g. {loading: true, success: false} to {loading: false, success: true}, and if so, set the local modalOpen state to false
Concerns: brittle, error prone, strong coupling between useEffect hook and redux state and how the state transitions from one into another.
Option 3: Submit the request in the component, don't use redux at all.
Opening and submitting the modal would trigger the following sequence of events:
Open the modal, which changes some local "modalOpen" state to true
Call fetch and submit the post request
In the .then() callback, check if the request succeeds. If it does, set the modalOpen state to false
Concerns: looks like an anti-pattern, because I'm calling fetch in the component itself.
What would your recommended approach be, and why?
I'd go with Option 3 Because It's the simplest and most straightforward way to go about it. The React Documentation Has an example of making an API call from within the a component so I don't think its an anti-pattern.
Your concern in option 1, is perfectly valid. Modal state should be localised to the Modal and not to the Global state stored in Redux. Option 2 is similar to option 1
Option 3 should be good per your context. It's okay to use fetch in the component itself since you only need it there. Only use redux or any global state management if you have data that is used across multiple components in your app.
I would choose option 1 if your application if sufficiently large since fetching data from store may appear in many pages. In this way, you can reuse the modal.
However, if the application is not very large, I may probably use option 3 because as #seyi_adel said, it may be more convenient and straight forward.
I am new to React and want to understand the difference from classic MVC.
I want to create a simple components that loads some data initially and renders let say a grid.
On some state or prop change it will reload the data and re-render.
What is the best approach in react from below two options?
using the lifecycle events to load the data, update some state and render while in another event will show some loading opacity.
Work with redux and react-redux? but in all example I cant see API calls.
Is this the role of a middleware (Thunk?)?
Will appropriate an explanation.
Both the approaches are correct. It depends on your use case. If you can avoid using redux in your app, use the lifecycle methods to make API calls (also called subscriptions in react documentation). If you think your app has many components and different components needs to share a state, then use redux.
You should also look at React hooks https://reactjs.org/docs/hooks-reference.html
You can use Effect Hook https://reactjs.org/docs/hooks-effect.html to make API calls and update your component's state.
Update:
Both Thunk and Sage are used to manage side effects in your application (making API calls from here). I've used saga, I don't know much about thunk.
How you would use redux-saga:
Say if you want to get some data for display on a button click, this is how it works:
On button click you dispatch an action, say GET_DATA
Your redux reducer will change some state on this particular action, say isLoading=true
You can use isLoading in your component to show a spinner/overlay
At the same time saga will listen to GET_DATA action and make the API call
If success, from Saga you'll dispatch an action, say GET_DATA_SUCCESS with the data from API call
Reducer will change isLoading=false and set the data in state, say apiData = { ... }
If failure, from Saga you'll dispatch an action, say GET_DATA_FAILED with the error code/message
Reducer will change isLoading=false and set the error in state, say apiError = { ... }
You can now use isLoading=false in you component to remove spinner and display the data (apiData) or error (apiError) in you component.
You can go through this tutorial to learn more https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html
I'm wondering what is the best way to implement CRUD operations in React Redux in case of List of entities.
Requirements:
1. Every row contain an entity
2. Changing a value in a text input trigger a PUT call to BE
3. Every row has Delete operation trigger a DELETE call to BE
4. Form has an ADD action trigger a POST call to BE
Notes:
1. No single Submit button
I thought about Redux Form for that but since I don't have a single submit operation I find it less appropriate (Feel free to correct me)
You can use Redux Form for that. If you setup a validator for the form, you can define if a field is dependent on another. Redux Form will run this validator for each change in any field.
You can setup something like Redux Observable or Redux Thunk to submit the form on Redux Form's CHANGE action when there are no validation errors in the form.
This way, you will submit the form on change, only if all the related fields are also filled.
I'm new to Redux. This is how I would do it. I will keep a state in the reducer which is called "personList". I will put all components in a container and map the personList to a property of the container called "propPersonList". When I create the ListItemComponent, I would also pass the index of the person in the list to the component as a property "propIndex". The onChange handler of the two inputs will dispatch an action with payload {index: this.props.propIndex, value: event.target.value}, then trigger a PUT request to backend (use lodash module to throttle it instead of triggering it everytime the input changes). The reducer will take care of the actions and update the state according to the payload. The add button will dispatch another action and the reducer will simply add an empty entity to the state, then trigger a request to the backend. The remove button will dispatch an action with the index as the payload, and the reducer will remove the corresponding entity from the list.
I'm trying to wrap my head around Facebook's Flux...
Say I have an app with a side menu that can be hidden and shown via a button in the header.
My header is one component, my side menu is another component.
Currently my Header component just sets a class on the HTML div side menu element which gets animated to hidden by CSS.
What's the general idea here?
ReactJs doesn't really care about how it gets its data (how it's data is getting passed in or how that data should be handled across the web application). That's where Flux comes in, it creates a functional approach on how data is handled. Data-flow is essentially:
Action -> Data Store -> Component
Mutation of data happen through calling Actions. The Data Stores themselves have to listen on the actions and mutate the data within the store. This keeps the data structure and logic flat.
In your case, your dataflow would probably look something like this:
Header --> User Click --> Fires action --> Updates store --> Side menu listening and responding to that store change.
Your case is a simple example which you probably don't really need Flux. I think it's easier if you have a parent component that maintains the view state logic, and use props/callbacks for the 2 children components (side menu and header). But a more advanced example that you need to make ajax calls and maintain session, Flux would become useful. Like if you have a Login Component, and you want to show different side-menu options and header options depending on user:
Login Component --> User Logins --> Calls Action #signIn --> Showing Loading State
--> Dispatcher handles action (make api call to authenticate user and load user data)
On success (for the api call), alert sessionStore, and populate store with data
On error, maybe fire another action that says login failed or something
SessionStore ---> Header Component (Listens to Store) --> Update view based on store information
---> Side Menu Component (Listens to Store) --> Update
speaking more general:
flux is a software architecture for a unidirectional Dataflow. It's Chain is Action -> Delegation -> Store -> View... The action - for example a Button Click - gets delegated to stores where your applicationlogic and data is kept... here your action and data will be changed and processed. The store eventually emits an event which views (for example react components) previously registered on with a callback. In this callback you can GET your data from your stores. It is important to mention that you can only access the stores READ-Only.
So for your case... if you want component A to affect component B you will have to register component B to the store eventEmitter and GET the desired data from the store. Once component a triggers an action it gets delegated to the store, your functions are performed and eventually the event gets thrown that starts component B's callback.
Hope this got clear enough... its way cooler with some nice drawings.