Losing a part of my state in Redux Toolkit - reactjs

I am trying to store the cart state for an ecommerce project. This is my first time using Redux Toolkit. In the first couple of images you can see the setup for the states and what the localstorage looks like when starting.
Application part of Chrome after clearing cookies
cartSlicer for Redux Toolkit
store.js
storage.js
Then, after using the application for a bit, I seem to lose the cart_total, cart_quantity and active states, leaving only the "mother" cart state that encapsulates all the states.
As you can see, I no longer have the objects from the initialState, only "cart"
This causes the application to break, since there is no longer a cart.cart level in the localstorage, like in the first image from the dev tools, which causes me to get undefined-errors.
I'm sure this is because I'm probably making a stupid mistake in how I'm setting things up. Any help would be greatly appreciated! If anything was unclear, please let me know!
Best regards, Ragnsan

Update!
I seem to have solved the issue. I figured out that the state was lost every time I tried to use the removeFromCart dispatcher. I changed it to:
removeFromCart(state, action) {
const index = state.cart_items.findIndex((item) => item.id === action.payload);
state.cart_items.splice(index, 1);
},
Can someone explain why this worked as opposed to:
return state.cart_items.filter((item) => item.id !== action.payload.id);
Either way, it worked!

Related

Why redux actions needs to be serializable?

https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants
While it is certainly possible to manually create action objects everywhere, and write each type value by hand, defining reusable constants makes maintaining code easier.
I don't feel easy at all. 95% of my actions are used once or twice. Anyone feel writing actions are beneficial?
Background
I got mad writing redux actions. Even for libs like zustand need action. So I decided to write an anonymous function to automatically change state for me. Hence the warning.
reducer: (state, action) => {
let newState = { ...state };
if (action.type === "func") {
newState = produce(state, action.func); // import produce from 'immer'
}
return newState;
},
Yes it is possible and can be done but serialization of actons enable several of Redux's defining features, such as time travel debugging, and recording and replaying actions. As an example: time travel debugging means redux knows when new thread for a specific time is resolved and can be checked back by the store to re-render the Components. Writing it in un-serialable way, redux does not keep this track.

Devtools for React Easy State?

i just switcher from redux, is there any tooling available, to inspect or even manipulate the react Easy State stores for dev purpose or do you have any good practice Tipps to do so?
Is ist maybe possible to console.log the current State on every change?
We don't have a devtool yet but it is an often requested feature. It's on our agenda and we are already collecting data about what people expect from a devtool. Sooo... what are the must-have features in a React state devtool to you?
About the timeline: we will release better docs, a linter, and probably strict-mode before a devtool. We already have a very basic devtool primitive (which just logs a lot of data) that could be used in the meantime. It would never be an official API though and we would just remove it in a later release. Are you interested? Should we release it as a temporary solution?
Is ist maybe possible to console.log the current State on every change?
Sure:
import { store, autoEffect } from '#risingstack/react-easy-state'
const myStore = store({
name: 'Bob'
})
autoEffect(() => console.log(JSON.stringify(myStore, null, 2)))
// logs `{ name: 'Ann' }`
myStore.name = 'Ann'
(I am an author of React Easy State)
If you're using global stores, e.g.:
const myStore = store({
a: 1
});
You can assign them to the window object so in your chrome/firefox devtools you could do something like:
window.__EASY_STORES__ = {
MY_STORE: myStore
}
You can then mutate that object in the console and it should be reflected in the rendering if your components are wrapped in view.
Other than that there's currently discussion around building a whole suite of devtools in the community, but at the moment we don't provide any out of the box inspector or dev tooling around the library.
It is indeed possible to log state changes using middleware. A simple logging middleware can look like this (it's typed in Flow):
export default (store: Store<ReduxState>) => (
next: (action: Action) => ReduxState
) => (action: Action) => {
console.log(`dispatching: ${action.type}`)
const result = next(action)
console.log(`next state: ${JSON.stringify(store.getState())}`)
return result
}
Manipulating is another thing. You could eather create a "cli" - I've recently done this in a project. It's basically just a JS function exposed to the browsers console.
Or, what I would suggest is using a browser plugin. The most commonly known is probably "Redux DevTools" which is available at least for Firefox and Chrome. It gives you CRUD-control (create, read, update, delete) over redux-state.
Edit: Since I fataly misread your question, this comment on GitHub might interest you. Seems not to have very active maintainers^^ But sorry, I don't know anything about easy-state.

Redux Offline issue with rehydrating reducer to null

I am using redux-offline, below is how I am creating my store
let customConfig = {
...offlineConfig,
persistOptions:{
key: 'root',
transforms: [immutableTransform()],
},
returnPromises : false,
persistCallback : () => {this.setState({rehydrated : true})}
};
const { middleware, enhanceReducer, enhanceStore } = createOffline(customConfig);
let middlewares = applyMiddleware(offlineCommitHandler,thunk,middleware,);
store = createStore(enhanceReducer(IndexReducer),undefined,compose(enhanceStore,middlewares,persistAutoRehydrate({log:true})));
I have multiple reducers.
The issue occurs only in rehydrating one reducer, for ex : reducerA
I placed a debugger in autoRehydrate
When opening the app first time it merges the data for reducerA
When opening the app second time inbound state for reducerA is
null.
I never did offline config but I ran into similiar problems with redux-persist.
So first of all you want to make sure that your debugger and your device/emulator are not drifting away in time. This would cause me problems all the time, simply restarting the emulator and chrome tab which I was using for debugging would solve it.
Second, you want to check if you don't have any errors in your reducer. In my case, I was not following the immutability pattern and that would sometimes cause redux not to persist my state, as it did not see any difference between the old state and the new state.
For anyone looking for answer to similar issue.
My issue was that the data i was trying to store was hitting the max storage limit for asyncStorage .
https://github.com/rt2zz/redux-persist/issues/199
I had to shift to using filestorage instead of asyncStorage to get redux persist store the data

How to update Fabric UI TagPicker suggestions from redux-saga

A Office Fabric UI TagPicker is an input field that shows matching suggestions in a dropdown to what has been typed in. I can fire a saga (via onResolveSuggestions) to get suggestions from the backend. Later that saga fires a succeded action which can then update the redux state. But how does that state change update the TagPicker's suggestions. I would like to specify the piece of state that the TagPicker should be connected to but that doesnt seem to be possible. or? (react,redux,saga newb)
Maybe my method help someone. I understood that onResolveSuggestions should definetly return suggestions. I think it's not intended to work with redux-saga. But TagPicker has componentRef. I saved tagpicker's node and did next:
componentDidUpdate(prevProps) {
const { suggestions } = this.props;
if (!isEqual(suggestions, prevProps.suggestions)) {
this.tagPicker.updateSuggestions(suggestions, true);
}
}
isEqual - example method for compare
updateSuggestions - tagpicker's method (true - force update)

Redux avoid stale data?

I'm trying to implement, let's say Twitter. I'm doing something like
initialState = {
tweets: {id => tweet}
}
then, a user goes to his timeline, now the action fetchTweets fetches all his tweets. However, then he can post a tweet, tweet T. But if I don't manually insert the posted T into state.tweets, he will not see this tweet in his timeline.
So here comes the question, when a user did some actions on his page, is that a good point to refresh the data? How does redux avoid data stale in this kind of case?
Thanks!
It's a bit of a paradigm shift when using Redux, but you don't want any functions to be your state. So, that initial state should actually just be either null or an empty object (depending on the design of the components that receive those props). But to answer your question a bit more directly, if you want to make sure that data stays "fresh" you need to make it happen. There is no magic in Redux, which is a GOOD THING.
However, if you design your code properly, the user shouldn't experience something resembling a full page refresh. At a high level, here is how I might design what you are describing.
Write actions for requesting and receiving tweets, i.e.:
export function requestTweets() => {
return {
type: REQUEST_TWEETS
}
}
export function receiveTweets(tweets) => {
return {
type: RECEIVE_TWEETS,
payload: tweets
}
}
Then wrap that in a "public" function that can be reused wherever:
export const fetchTweets = () => {
return (dispatch, getState) => {
dispatch(requestTweets())
//network code here is pseudocode
fetch('https://tweeter/api/v1/tweets')
.then(data => dispatch(receiveTweets(data))
.catch(err => displayErrorMsg(err))
}
}
Then in your action handlers just reduce the tweets into the next state.
Now with fetchTweets, you can call that on the first load, after posting or on an interval. The nice thing is React will handle the diffing well for you and not re-render the entire page. It's just up to you to design it well so the user notices when and where new tweets come in.
Hope that helps!
Redux manages your state for you. It tells anyone who wants to hear about any changes in the state, such as React-Redux.
It does not do anything to help you with getting data, such as tweets. Nor does it help you decide when to get this data.
You'll have to decide for yourself when to do this and you can use setTimeout or anything else you feel like.
It's probably best if you manually insert the tweet into the state rather than refetch when you post. It's so much more responsive.

Resources