I have a project that uses React and Redux. I have multiple React components that need to use a common method that will scrape data out of the Redux Store, build a request object and fire off a rest request to the server.
I wouldn't want to write the method that does this more than one time. So, should this method be it's own React component, or should I just put it in a common javascript file? I'm not sure what the point of having a component would be if you're not rendering any JSX. On the other hand, if I put it in a common javascript file, is it possible to wire up redux to that file to get access to the states in the store?
Thanks in advance.
Adding the redux-thunk middleware lets you dispatch functions, which then get access to dispatch and getState(). From there you can do anything you want, such as using selector functions to extract pieces of state that you need, and making AJAX calls. The thunk action creators can be passed to components as props, including binding them to auto-dispatch:
function someThunk() {
return (dispatch, getState) => {
const state = getState();
// do anything you want here
}
}
const actions = {doStuffOnClick : someThunk};
export default connect(mapState, actions)(MyComponent);
Further resources:
redux-thunk is described in its repo at https://github.com/gaearon/redux-thunk .
I have a gist demonstrating some common thunk usage patterns at https://gist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857e.
My React/Redux links list has links to articles discussing thunks and side effects in the Redux Side Effects category.
It should not be a Component because, as you said, there is no visual aspect to it.
Create a new action that does just that and dispatch the action from anywhere you need. This action could check the store to see if the action has already happened and then do nothing (or refresh).
The module that uses import {createStore} from 'redux' creates your store. Import the created store in the action module and use store.getState() to inspect the current state of your store.
Related
I'm currently building a React application based on https://github.com/react-boilerplate/react-boilerplate-cra-template.
This boilerplate, uses Redux with slices. Which works fine, as long as I want to update the state from within a React component. However, I am struggling with updating my application state from somewhere else. In my particular case I want to dispatch a logout event as soon as I get a response that I am unauthorized, basically resetting the application state.
Now this obviously can happen in any API request and therefor I don't want this to handle within the React component and rather handle it in my API library that handles API requests.
From what I've read so far, I should be able to dispatch an event by simply accessing the store. In this boilerplate the store is defined in the src/index.tsx file. So after adding the export keyword to it I thought I would be able to do this:
import { store } from 'index';
import { appActions } from 'app/slice';
console.log(store.getState());
store.dispatch(appAction.logout());
Somehow the state here is always undefined, even tho there is a state when I access it via a React component. Also the reducer called above never picks up the dispatched event. I also tried to encapsulate it with a timeount, in case this is just because the store isn't initialized yet, but that's not the case.
I'd appreciate your help :)
Please try to check the path is correct to get to the store.
After that please try again. I think your method is right.
If it is not working, please try to use the require method
require('index');
require('app/slice');
console.log(store.getState());
store.dispatch(appAction.logout());
Ok, here is how I finally made it work:
I imported the React hook of my slice into the src/app/index.tsx file
import { useAppSlice } from 'app/slice';
export function App() {
// use the React hook
useAppSlice();
return (
<BrowserRouter>
...
</BrowserRouter>
);
}
Even tho I'm not using the slice in this particular controller, it somehow "connects" with the store, so that I can use the slice from within any sub-controller or any library.
I recently tried something in my project and I was quite surprised that it worked. What I did was this :-
let result = {};
Axios.post("/auth", newUser).then(res => {
// console.log(res);
result = res.data;
this.props.signupUser(result);
});
The above code was written inside onSubmit event handler of a form in react. I wanted to get the response from the POST request and store the response in redux store and I tried the above code and it worked. The result was stored in redux store. So my question is was this supposed to work? and if yes then what's the purpose of redux thunk?
signupUser is a simple action creator, a function which returns a plain object and the variable newUser is an object which contains the form data.
The purpose of thunk is to give you more control over the async actions. While your code works, consider some more advanced requirements:
A different React component is supposed to show a loading animation while the request is in progress
You you want to track all api error responses somewhere
after the user has signed up, you want to trigger other requests for unrelated resources
Thunk facilitates all of those things in a more convenient way. You can also look at the current redux state at any point with getState in thunk actions. In general, it's better to separate concerns: React components show a signup form and are wired up with redux actions. The actions take care of api requests and data handling. Nothing is stopping you from writing all that code inside of a React component, but in a larger app this will get out of hand quickly.
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
Let's say I have this code below:
switch (action.type) {
case "GET_LIST":
// update state
break;
case "GET_LIST_SUCCESS":
// update state
break;
case "GET_LIST_ERROR":
// update state
break;
default:
return state;
}
Before this, I've already set-up some action creators (with a thunk middleware for async requests). So the flow would be either GET_LIST > GET_LIST_SUCCESS OR GET_LIST > GET_LIST_ERROR.
Now in my React component, I want to do something depending on which action type was dispatched in the end (either success or error).
Is it a good practice to use the action type themselves or should I just use the store state for my condition? In this example, my store would have an error property, which I can use to detect whether there's an error or not.
So it's either (using action type):
if (actiontype === "GET_LIST_SUCCESS") {
// do something
}
OR (using the store state)
if (this.props.list.length > 0) {
// do something
}
Which is a better practice and why?
Just my opinion, but one advantage of using Redux over storing data in component state is that you separate the concern of how to handle data updating from view layer (React) to Redux; React component should only know if the data has been changed, not how it is changed. This de-couples the data layer and view layer in frontend, and helpful when you need to execute a chain of actions to update state (e.g. fetching from API).
If you want to expose current Redux action type to React component, you have to log the action somewhere in your app, since I don't think Redux exposes current action to view layer. In addition, this also reveal too much info of how Redux handles data flow.
Common practice is saving fetching state in boolean, and error log, e.g. isFetching and fetchListError, update those values along the fetching process, and pass those value to view layer for display.
From my understanding, we have react app with components and redux app with store. We use
another library react-redux to bind react app and redux app. React-redux helps to use redux store state in react component and helps to dispatch actions to redux store from react component.
For handling asynchronous operation libraries like Redux-thunk is used and depending on the result of the asynchronous operation, these libraries dispatch action.
Answer to your question: React is not aware of which action was dispatched in Redux store as it is handled by thunk middleware. But using React-redux, React can know what is the current Redux store state after the action was dispatched by thunk middleware. So I think you shoud go with the second option. First option might be possible but it will need alot of hacking than simply using the first one.
I am reading this tutorial on writing Async Actions
http://redux.js.org/docs/advanced/AsyncActions.html
and based on this, I have a method called fetchPosts in my action. this method first dispatches a requestPosts action, then it calls the web service and finally dispatches receivePosts with the results.
My question is from where should I call this method so that when my application loads, the data is loaded from web service?
Here is some options depending from app logic
1) If you want access to posts globally, across all components
you can put fetchPosts right after creating store, example from
redux/examples/shopping-cart
const store = createStore(
reducer,
applyMiddleware(...middleware)
)
store.dispatch(getAllProducts())
2) If you want access to posts only for specific component/page
you can put fetchPosts call in componentWillMount method of specific component.
componentWillMount() {
loadData()
}
Some examples from redux official examples
redux/examples/real-world/containers/RepoPage.js
redux/examples/async/containers/App.js
redux/examples/real-world/containers/UserPage.js