Let’s say I don’t use Redux (and therefore no Redux Thunk involved) in my application, and instead, I manage my state with the useReducer hook.
The issue is that in the action creator, I want to access the state itself. Does the only solution is to give the state itself as a parameter to the action creator, or is there a way to get the same benefits of the Redux Thunk, and be able to access the state itself through some getState() function?
Create a reducer that accepts state & action and returns a new state based on the action (same as redux).
When you are calling 'useReducer' you should pass it the reducer you've built and the initial state.
You will get back the state and dispatcher (the function that will use you to update the state - same as redux).
Please find the following articles explain how to achieve it shortly and simply:
https://www.peanutbutterjavascript.com/roll-your-own-redux-with-usecontext-usereducer/?fbclid=IwAR2je-sa5UW_5elE8UlkcUfZEzYjiwBO44P4smsn3NPznUiMS3EZEKsILEw
https://medium.com/#martin.crabtree/react-creating-a-redux-like-global-state-with-the-usecontext-and-usereducer-hooks-89aa2b27dbc5
Related
I have a react project configured with redux for state management.
For api calls I use a file called axiosInstance. In this file I need to have access to redux store (and I have access importing store and using getState - store.getState()). Now the problem is that I want also to update the redux state from this file (axiosInstance).
How I can update redux store from this file (which is not a react component) in a efficient method?
Okay, I assume that you are using Axios for the network calls.
tl;dr
Use store.dispatch(action) and action to make changes to store state
Yes, the store can be accessed with store.getState(), you can also change state with store.dispatch(action). as per the docs
Dispatches an action. This is the only way to trigger a state change.
The store's reducing function will be called with the current getState() result and the given action synchronously. Its return value will be considered the next state. It will be returned from getState() from now on, and the change listeners will immediately be notified.
This happens because of the functional paradigm that redux follows (google for more).
Now, the action has to be defined with an actionCreator, or simply you could call .dispatch() with an inline object with one string property as {type: 'name-of-action'}. This prompts the store to change the state.
You may require redux-thunk for async actions.
Conclusion:
Let's save some trouble here as you may have many calls to the store, you can create a context that handles the AxiosInstance (as there is already a different file for that).
Make a context in the AxiosInstance file and then you can start dispatching actions as per the network responses. this will save you a lot of trouble as the state is updated by redux without actually looking at it much.
How to get latest updated react component state (after all the state changes are done) and put the same object in Redux.
Get the latest state and dispatch an action (with a copy of current state) only once instead of dispatching the same action from different methods where state is getting altered ?
Is there any efficient way to achieve this ?
First If your state doesn't need multiple pages then no need to store the state in the redux, use local state.
But if you want to use redux and want latest state, then if you want this state in the stateless component(functional) then you can use useSelector redux hook for the latest data, and if you want the state in the stateful component then use mapStateToProps.
useful links:
for hooks: https://react-redux.js.org/api/hooks#useselector
for mapStateToProps: https://react-redux.js.org/using-react-redux/connect-mapstate#defining-mapstatetoprops
I have some variables which are controlled by React Context through React.createContext() inside a functional component. I'm also using redux-saga, so my question is are there anyway to access this context value in redux-saga function. Storing the values in Saga middleware isn't an option bcoz, the context values keeps changing.
The only option I have is to pass the context value to action object payload when dispatch an action. So in redux-saga, we can use it in action parameter.
I have visited this link for Class component, which doesnt work for Functional components.
Access context data in sagas
Yes. I finally created a package to get around this, just use useContext when creating the call config.
https://github.com/alisternorris/react-outside-call
After reading redux official docs, i'm unable to get the différence between action creator function and simply action.
they are complementary ?
Actions are payloads of information that send data from your application to your store. Actions are plain JavaScript objects. Actions must have a type property.
Action creators are exactly that—functions that create actions.
Action is message that we send to redux store. It can be of any type like mostly object which contain payload and action type
Action creator is function which create and return function dynamically.
An action in Redux is only a function. That it. It has a type and a potential payload.
Once an action is "dispatched" using redux dispatch method or u can do the easier bindActionCreators which takes care of the dispatch call for you, redux reducers are all fired and then we check for a match in the switch tree of the reducers.
If there is a match in the reducers the new state in the reducer is set and it triggers a render update on react.
I am working on my first React Redux project.
The project depends on a server to get its data and therefore there is also a server API that needs to be called in order to get those data.
My question is about initialising state.
There are 2 ways I can think of initialising state:
1.) First pass an empty object {} as the initialised state of the Redux store then inside componentDidMount that is where I call the API to access the data in the server and then update the state of the store/app then.
2.) In the reducer of the Redux app call all relevant server method (e.g. getCategories(), getPosts(), etc.) then compose a object with all of the data e.g. {categories: categories, posts: posts} then pass this object to the reducer as the initial state.
Which way is the recommended way for Redux when dealing with data stored in the server?
If there is a 3rd or 4th way that is the Redux way or the recommended way then please share your knowledge. Thank you.
The way I work with data coming from the back end, and as far as I know is also the suggested way, is this:
In the componentDidMount method call a thunk action creator. you can read more about them in this link.
Inside that thunk action creator you first dispatch a REQUEST action, then perform a fetch to access the back end and when the response arrives you handle it on either the success or error handlers. Depending on the handler executed you dispatch either a SUCCESS or an ERROR action (and you attach to it all the relevant information that is coming from the back end so the reducer can access it).
In your reducer you write code to handle all the above actions (REQUEST, SUCCESS and ERROR). Each handler will transition your state, for instance the REQUEST can set an isFetching flag to true that will let you show a spinner in the UI, and the SUCCESS can set that flag to false and populate the state with the data coming from the back end and passed to the reducer using the action dispatched.
Once your reducer is updated, you will access that updated state from the UI, for instance using the connect react-redux function.
Regarding the initial state, it should represent a default state. for instance, it will have the isFetching flag in false and, if you are fetching a list of foods from the back end, then that list could be an empty list in your initial state. This is just a for instance of course. You need to set an initial state that makes sense to your app.
I hope this helps you.
The first way is the better way of initializing state. Your component makes the necessary API calls in componentDidMount and passes the data to Redux as payload of actions which the reducers use to update the state of your application.
The second way is not advisable. According to the Redux docs:
The reducer is a pure function that takes the previous state and an action, and returns the next state.
(previousState, action) => newState
...
It's very important that the reducer stays pure. Things you should never do inside a reducer:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
Edit:
You can also use thunk middleware and async actions to do API calls as explained in the Redux docs and #DiegoTArg's answer.