React Redux, replacing state history - reactjs

I am developing an app where I have one Canvas.
Users can choose to duplicate this canvas to save their achievement.
My question is when they come back to this canvas, is it possible to erase the actual state history and replace it by the canvas one in react-redux ?
Is there an efficient way to replace a state history by another in redux?
I could try by directly changing it in the store, but it's a bit dirty...
Here is some snippets of my code:
Store
const store = createStore(combineReducers({
historyCanvas,
canvasDrawing
}));
Reducers
var stateCanvasDrawing = {
lines = [{id:1, strokes: [..] }, {id:2, strokes: [..] }]
}
var stateHistoryCanvas = {
history = [{id: history1, state: {present: [..], past: [..], future:[..]}]
I store states in the historyCanvas reducers:
Then by clicking on a icon, I am able to retrieve the state I want to replace:
var tempState = state.stateHistoryCanvas[0]['state'];
And then I want to do something like that:
store.getState()['stateCanvasDrawing'] = tempState;
in order to replace the actual state by the state I retrieve.
That would be easy with just redux.
But I'm using redux-undo, so how could I copy the entire history I have stored in 'stateHistoryCanvas' to the new state? I don't want to copy only the
but also the state['future'] state['past']
Hope it's clear,
Thank you all,

Related

How to access arcgis map via components?

The code below is taken directly from arcgis via react on how to display a map.
If i wanted to say, zoom in to a set of coordinates, but the code for that was set in another component, how can i get that component to talk to the map here in this component?
import Map from '#arcgis/core/Map';
import MapView from '#arcgis/core/views/MapView';
const map = new Map({
basemap: "topo-vector"
});
const view = new MapView({
container: "viewDiv",
map: map
});
I resolved this by using redux toolkit to set the map as a global state object.
The entire map view is set in a useEffect, once i initialize each of the views, i dispatch the map view to a reducer in rtk.
dispatch(updateMapViewState(view));
updateMapViewState: (state, action) => {
state.view = action.payload
},
Then, when i want to use the map in a separate component, i do:
const view = useSelector((state) => state.MapSlice.view);
In this way, all components can access the map outside of the useEffect in the map component, and can manipulate it without creating a new map view. This worked for me. I assume you could probably do this with context api, but we aren't using that as a global state manager.
This may not be the recommended or best way to achieve this, but I had success by passing the view object from the map component back to the parent component, then saving it to the parent component's state.
// in App.js
saveViewToState(view){
this.setState({view: view})
}
<MapComponent saveViewToState={this.saveViewToState}/>
// in MapComponent.js
let view = new View()
this.props.saveViewToState(view)
Then I was able to interact with the view object from the parent:
// in App.js
this.state.view.extent = {xmin: 1, ymin: 1, xmax: 2, ymax: 2}
This doesn't work perfectly (for some reason I can't call view.goTo, but view.extent works). I'd be keen to hear if there is a better way to achieve this.
Still looking for a clear answer to this problem.
Have not found an example separating the map/view creation and adding layers into differing components.

How to set initial slice state using slice reducer

So, I've got a redux slice, where there are two reducers, setTodos and addTodo, the initial state is set to be empty, but soon updated using the reducer setTodos, the data of setTodos(dispatched from a component) is fetched by a network call, so it is an asynchronous task. The data is updated properly, but when I try adding a new todo, the addition is not reflected on the screen as it should, perhaps it is displayed only on reload because setTodos is executed again and the state is updated accordingly.
const myTodoSlice = createSlice({
name:'Todo',
initialState:{todos:[]},
reducers:{
addTodo:(state,action)=>{
state.todos.push(action.payload.todo)
},
setTodos:(state,action)=>{
//Approach 1 of setting the initial todo state.
state.todos = action.payload.arrayOfTodos
//Approach 2 of setting the initial todo state.
// state.todos.push(...action.payload.arrayOfTodos)
}
}
List rendering code:
const selector = useSelector((arg:RootStateOrAny)=>arg.todos.todos)
return(
<React.Fragment>
{selector?.map((item:RootStateOrAny) => <TodoItem key={Math.random()} title={item.todoTitle} desc={item.todoDescription} />)}
</React.Fragmnet>
)
Currently, I'm following approach 1, but by doing so, I'm unable to render new additions on the screen. When I tried using approach 2, I'm getting errors mostly related to re-render depth exceeded.
I'd want to know by following approach 1, why is the addition not rendered, and what changes can I make to get the desired result?
Thanks.
The issue is that React sees the same array reference (because the push is a mutation operation of the existing array instance) and ignores the rendering.
Instead of
addTodo:(state,action)=>{
state.todos.push(action.payload.todo)
},
Try like below which creates a new array instance with adding the new todo item (concat returns a new array with the new item without mutating the existing one).
addTodo:(state,action)=>{
state.todos = state.todos.concat([action.payload.todo])
},

What is a State Tree in React JS

I am new to ReactJS and finished parts of my ReactJS courses that I was taking until I came across Redux where it was talking about uses of Single State tree. I want to know what a state tree actually means
I agree #A.M Usmani
A state tree isn't anything special, it's literally just the state object. A 'single state tree' refers to the fact that in Redux, you have ONE state tree (object) which everything connects to. A single state object that acts as the universal source of truth for your application's stateView
create visualization for the state of each component eg like below picture and
Categorize each reducer like below
const headerReducer = combineReducer({
menu: menuReducer,
search: searchReducer,
location: locationReducer
});
const rootReducer = combineReducer({
header: headerReducer,
login: loginReducer,
footer: footerReducer,
common: commonReducer,
product: productReducer,
catalog: catalogReducer,
payment: paymentReducer
});
Please go through this link you will get good understanding : https://www.freecodecamp.org/news/the-best-way-to-architect-your-redux-app-ad9bd16c8e2d/

redux, normalizr, access store mapDispatchToProps

If I have a data object like below
{
items: [
{id: 1, selected: false},
{id: 2, selected: false}
]
}
Running this through the normalizr would get me something like
{
entities: {
1: {selected: false},
2: {selected: false}
},
result: {
items: [1, 2]
}
}
Typically I would have an Items component that maps the state to props like this:
const mapStateToProps = (state) => {
return state.result;
};
The problem I have is on the Items component, I would have a save button that needs to send the state of the store to the server.
I haven't seem to be able to find a good way to access the store to denormalize the data before sending it to the server.
1) I prefer not to include the Entities in MapStateToProps because there is no need for the items component to know about it.
2) MergeProps also seems suboptimal due to performance issues.
Right now I'm accessing the store directly by simply importing the store and accessing it in my dispatch methods which seems to work, but that breaks the separation of concern, is there a better way to do this?
Judging from the description of your problem, I believe you send the store's data by a method inside Save button component, or another React component. If you do that, you must expose the sending data to that component no matter what.
An alternative solution is to handle the API call by a middleware. Libraries such as redux-saga or redux-thunk can handle your case neatly. They are designed to handle async flows, and provide access to the store.

React with Redux Update only state

I'm working on integrating Redux in an already finished SPA with ReactJS.
On my HomePage I have a list of the 4 newest collections added which on render, I fetch with axios from my database. These are then saved in Redux Store and displayed on the React UI.
My mapStateToProps look something like this:
const mapStateToProps = (state) => ({
credentials: credentials(state),
collections: collections(state)
});
Where credentials is irrelevant and collections is:
const collections = (state) => {
if (state.collectionsHomeViewReducer.fetching === true) {
return {
fetchingCollections: true
}
}
else if (state.collectionsHomeViewReducer.data) {
const response = state.collectionsHomeViewReducer.data;
return {
collections: response.collections,
fetchedCollections: true,
fetchingCollections: false
}
}
else if (state.collectionsHomeViewReducer.fetched === false) {
return {
fetchedCollections: false,
fetchingCollections: false
}
}
};
What is it I want to do:
Update the store state every time another client, or the current client, adds a new collection. Moreover, I do not wish for the UI to update immediately after I dispatch(action), I want it to update when a user refreshes the page or when he navigates to another view and returns ( I believe what I'm trying to say is when componentDidMount is called ).
What have I achieved so far:
By using socket.io, I
socket.emit("updateCollectionsStore")
socket.on("updateCollectionsStore")
and
socket.broadcast.emit("updateCollectionsStore")
in their respective places in the application. The final call of
socket.on("updateCollectionsStore")
after the broadcast, is in the main file of the page, app.jsx where the store is also located. The function there looks like this:
socket.on("updateCollectionsStore", () => {
store.dispatch(getCollectionsHomeView());
});
The store is updated and everything works fine, as viewed from the Redux Dev Tools.
What I can't seem to figure out is to tell the props not to change due to the fact that mapStateToProps is called every time an action is dispatched.
Why do I need this: The HomePage can deal with a continuous UI update and data fetching but I also have a page ReadAllPage where you can real all collections. The problem is if there will always be the newest post on the top, whenever a new one is added, the current one is pushed downwards. In case somebody had the intent to click the one that was pushed down, now he might have accidentally clicked the one that took its place, which is not wanted.
What else should I do different or further to achieve the result I want?
Thank you.
According to your needs, I would have two properties in the state. First is that is currently visible on the HomeView and the second is that is updated via sockets. Once a user navigates to the HomeView you can just replace the first collection with the second one.

Resources