Redux: build a reducer for a subelement of a main reducer - redux

Possibly a silly question. I have a Redux reducer built from an Immutable.js record:
export const Editors = new Record({
'editors': new List(), // this is a list of Editor items below
})
export const Editor = new Record({
'id': null,
'state': EditorState.createEmpty(),
'annotations': new List(),
});
I've structured things this way, because I expect the application that I am building to have many editors.
However, I want to write an updateState action that updates the state of an individual editor. I imagine that it would be much easier to write this if I was able to write reducer code that acts on a specific Editor rather than on the list of Editors in my Editors reducer. Is there a way to write reducer code so that I can just update state on a field in an individual editor, rather than finding the editor in the list, removing it, updating it, re-inserting it, etc.?

export const Editors = new Record({
'editors': new Map(), // this is a list of Editor items below
})
export const Editor = new Record({
'id': null,
'state': EditorState.createEmpty(),
'annotations': new List(),
});
Then updating an editor becomes:
const updateEditorState = (Editors, id, editorState) =>
Editors.setIn(['editors', id, 'state']¸editorState)
Your naming is a bit weird, by the way. I would lower case Editors and Editor.

Related

Firestore data won't load until I change code file on React Native App

This might sound weird but my Firestore data won't display on my app unless I save my code files.
Here is my screen when I get to the screen for the first time. Also, the items under Today's Deals are hard-coded.
Then here is my screen when I save my merchant.js file in vscode.
const store = route.params;
const [items, setItems]=useState([])
let storeItems;
const getStoreItems = async()=>{
let merchantId_str = String(store.merchantId);
const response = firestore().collection('Items').where('merchantId', '==', merchantId_str)
const data = await response.get();
data.docs.forEach(item=>{
items.push(item.data());
})
}
storeItems = getUniqueListBy(items, 'sukiId');
storeCategs = getUniqueListByCateg(items, 'storeCateg');
useEffect(() => {
getStoreItems();
}, [])
I've tried to console.log(Items) as well when nothing loads and it's empty.
It seems that you are trying to modify the read-only state of items at
items.push(item.data());
Use the provided setItems function instead. Something like this should work:
let receivedData = [];
data.docs.forEach(item=>{
receivedData.push(item.data());
})
setItems(receivedData);
You should be receiving some sort of a warning message in the console though about this.
I believe your usecase is not suitable for "useEffect" hook.
What does useEffect do? By using this Hook, you tell React that your component needs to do something after render.
You may explore on "useState".
useState is a Hook that lets you add React state to function components.
Read more about useState and useEffect on the official React docs.

Best way to query for favorite list

users have the ability to set a item as favorite, when pressing the star icon they set of a Redux function that sets this as a local favorite and saves this in the Firebase Database as well;
-Userfavorites
--userID
---ItemID: true (or false if the disable the favorite later on)
This all works well, however I'm now trying to figure out how it is best to handle the information when it is retrieved from Firebase. On opening of the app all items are retrieved, as wel as the above UserFavorites list.
What is the best way to handle this in my Redux state?
Component: {ItemID1: true, ItemID2: true, ItemID3: false}
or
Array: 0.[ItemID1: true]1.[ItemID2: true]2.[ItemID3: false]
When opening an item I want to cross check the itemID that is opened, if it Exists in the UserFavorites list in Redux AND is set to true the icon should so different from a value of false.
What I have found is that I cannot look into the Redux state with a variable (like state.items.userfavorites.ItemID === true (Where ItemID is the variable of the Item ID that is opened.) What is your preferred way of working with a favorite function and am I on the right track with using the favorites list?
So I got this working yesterday. My Firebase Database still looks as above. Below is the Redux action. I create an array with this where every entry has the favID prefix followed by the key, which in my case is the itemID.
const resData = await response.json();
console.log('fetchFavorites action response data' , resData)
const result = Object.entries(resData).map(([key, val]) => ({
['favID']: key
}));
console.log('results' , result)
dispatch({
type: FETCH_FAVORITES,
userFavorites: result
});
Then on the detail page I use the following code to look if the currentItemIsFavorite.
const currentItemIsFavorite = useSelector(state =>
state.onlineItems.favoriteItems.some(item => item.favID === itemId)
);
After that generating the correct icon with this;
<Item
title="Favorite star"
iconName={isFavorite ? 'ios-star' : 'ios-star-outline'}
color='gold'
onPress={toggleFavorite}
/>

Immutable.js: create a list with one element

I have an Immutable record as follows:
export const Pane = new Record({
'id': null,
'editors': new List(),
});
where editors is a list of id strings associated with a pane.
In my Redux reducer code I have:
const pane = new Pane({
id: action.payload.id,
editors: new List(action.payload.editorId),
});
When the reducer is constructing the Pane, however, it creates the editors field as an Immutable List, as intended, but rather than having a single string, each character in the string becomes an individual item in the list.
How do I construct an Immutable List with a single object, as intended?
you just need to pass the List constructor an array containing your string(s).
assuming action.payload.editorId is a string, and not an array of strings;
e.g.
const pane = new Pane({
id: action.payload.id,
editors: new List([action.payload.editorId]),
});
For more information, check the documentation at https://immutable-js.github.io/immutable-js/docs/#/List/List

Ngrx Large Amounts of Data causes app to slow down

I have an app that loads some images with metadata. A single folder can be quite large (~100-142Mb) once loaded into memory. Previously, we were using a plain old javascript object to manage the state of the app and everything worked fine, but i'd like to gain the benefits of ngrx's state management.
I've discovered ngrx and it seemed to be a smarter option when it comes to state management. However, when i add these items to the state, the app hangs when adding images to the store and then performance slows down when accessing individual (and unrelated) flags from the store i.e. UI flag - draw is open.
1) Here "directories" is a Map < string, Directory > () object that is saved the the Store (~100-120Mb). Directory is a complex object with many nested values. Once images are loaded, and then added to the store, it a) hangs and then b) everything else (i.e. changing a ui flag) slows down.
return {
...state,
loadedDirectories: directories,
filesLoading: false,
};
2) The directories are then later accessed from the store.
this.store
.pipe(select(fromReducer.getLoadedDirectories))
.subscribe(loadedDirectories => {
this._directoryData = loadedDirectories;
});
Selector looks like this....
export interface ImageLoaderState {
loadedDirectories: Map<string, Directory>;
filesLoading: boolean;
errorMessage: string;
}
export class AppState {
imageLoader: fromImageLoader.ImageLoaderState;
}
export const combinedReducers = {
imageLoader: fromImageLoader.imageLoaderReducer
.... More reducers here ....
}
// Select Image loader state.
export const selectImageLoaderState = (state: AppState) => state.imageLoader;
export const getLoadedDirectories = createSelector(
selectImageLoaderState,
(state: fromImageLoader.ImageLoaderState) => state.loadedDirectories
);
Using angular 8 and the following versions of ngrx.
"#ngrx/effects": "^8.4.0",
"#ngrx/store": "^8.4.0",
"#ngrx/store-devtools": "^8.4.0",
Are there any better practices? i.e. Add each image, one at a time to the store?
The ngrx store is for application state and not so good as a document store.
Please see..
https://github.com/btroncone/ngrx-store-localstorage/issues/39
One issue I see is how you create your new state. You mention that when you create your new state, you do the following
return {
...state,
loadedDirectories: directories,
filesLoading: false,
};
I think you are creating an object with tons of key-value pairs, then recreating that work when you set the loadedDirectories property again. I'm uncertain about the performance costs of using the spread operator in the context of very large objects. I would suggest you focus on creating this property once. This might help you
Does spread operator affect performance?

What is a difference between mapStateToProps,mapDispatchToProps types and selector in reactnative

I am new to react native with redux. I am trying to figure out how all the pieces in react-native redux integration. The one thing giving me trouble is understanding the difference types and selector give me more details.
MapStateToProps -> has his name say, you can map state objects to props. Example:
You have a store like this:
{
name:'paul',
surname:'watson'
}
Then you need show in your component the name, so in your container you can access to this data stored in store with mapstatetoprops, like this:
const mapStateToProps = (state, ownProps) => ({
myname: state.name,
})
MapDispatchToProps -> thats when you need dispatch an action, you map an action to a prop to you can use in your component
You have an action like:
const setMyName = payload => ({
type: SET_MY_NAME,
payload,
})
then you need update your name in store when user click something throw this action, so you can map this action in a prop to call like updateName('pepito') with mapDispatchToProps, like this:
const mapDispatchToProps = {
updateName: setMyName,
}
Selectors -> it's just an abstraction code, selectors make your life more easy.
Selectors are functions that take Redux state as an argument and return some data to pass to the component, like this:
const getDataType = state => state.editor.dataType;
Thats a basic concepts, you should read oficial document and search, in internet have a lot of articles about this.

Resources