redux store change not immediately visible to component - reactjs

Im trying to create a formbuilder using drag and drop functions. Im maintaining the state using Redux. I have two items in initial state(allItems array and dragItem). My reducer looks like the following:
import { ActionTypes } from '../constants/ActionTypes.js'
const intialState = {
allItems: [],
dragItem: ""
}
export const builderReducer = (state = { intialState }, action) => {
switch (action.type) {
case ActionTypes.addItem:
return {
...state,
allItems: action.payload
}
case ActionTypes.dragItem:
return {
...state,
dragItem: action.payload
}
default:
return state
}
}
drag Item is updated on dragstart event everytime the user drags a component . all items is updated evrytime the user drops the component in workspace. once i drop the component store gets updated correctly . However im not immediately able to collect the changed store value . it is taking two drag and drops to get the store value . it says undefined at the first place i try to use it . on second drag and drop i get both the values together . Below image will explain what i am trying to do .

Related

How can a state be cleared when moving away from a page

I have created a Quiz app that tracks the correct answers in state called correct_answer. The issue is when the user leaves one quiz and moves on to the next one, The quiz answers are still stored from the last quiz.
I have tried using LOCATION_CHANGE from react-router-redux, but I am not sure I am using it correctly.
import { LOCATION_CHANGE } from "react-router-redux";
const initialState = {
questions: [],
answers: [],
correct_answer: []
};
export default function(state = initialState, action) {
switch (action.type) {
case "GET_QUESTIONS":
return { ...state, questions: action.payload };
case "GET_ANSWERS":
return { ...state, answers: action.payload };
case "CORRECT_ANSWER":
return {
...state,
correct_answer: [...state.correct_answer, action.payload]
};
case LOCATION_CHANGE:
return {state = initialState};
default:
return state;
}
}```
The app needs to clear the correct_answers state anytime the user moves away from the page.
Keep in mind that the redux store is an omnipresent data structure. The data persists regardless of any ui changes in your app, which includes local state changes in a component and mounting/unmounting components (unless you tear down your reducer, but that's not what you're doing at all).
As mentioned in the comments, it's your job to clear your state. Create an action that will reset the reducer. How you implement it is based on your exact implementation of your Quiz component(s).
How does mounting/unmounting/prop changes work when you switch quizes? Are you mounting an entirely new component or are you feeding new data into an existing component?
If the next quiz is an entirely new instance, then you call it when you unmount the prior quiz:
componentWillUnmount() {
this.props.resetQuizState() // your action that resets the data in your store
}
If it is the same component but new props are passed in:
handleNextQuizClick() {
this.props.resetQuizState()
// and then rest of data manipulation/calling/parsing
}
render() {
return (
<button onClick={this.handleNextQuizClick}>
next quiz
</button>
}

How to use redux saga in editable table efficiently

I have a multi page react application in which one endpoint has to show data in tabular form. Show I take GET_INFO action on componentWillMount of that endpoint. Now I have a reducer called table_info which has table_data array and shouldTableUpdate boolean in it.
My table is editable with edit and delete icon in every row. I am facing problem in update, on update I call reducer with action UPDATE_TABLE_ROW and if success than I do something like following :
//reducer.js
const initialState = {
table_data:{}, shouldTableUpdate:false;
}
export default function myReducer(state=initialState, action){
switch(action.type){
case UPDATE_SUCCESS:
// how to handle edited row here?
// also when I print my state of this reducer
// state becomes nested, so if one does lots of updates
// it will be become very heavy...
return {...state, shouldTableUpdate:true}
}
}
Can you tell how to handle update, delete, add on table using redux saga efficiently ? On googling I get naive examples only, so came to SO.
Note: Can't show the actual code as it's for my company project. Sorry for that.
Thanks.
Can you tell how to handle update, delete, add on table using redux saga efficiently ?
Well you can plainly manipulate the state object using a reducer only.
Comments:
table_data is a list and not an object.
I don't think you'll be needing shouldTableUpdate since state change in store will trigger a component update if state field is mapped in mapStateToProps.
So here's a basic template of adding, updating and deleting items via reducer.
const initialState = {
table_data: [],
};
export default function myReducer(state=initialState, action){
switch(action.type) {
case ADD_ITEM:
return {
...state,
table_data: [
...state.table_data,
action.item, // item to be added
]
};
case UPDATE_ITEM:
let updatedItem = action.item;
// do something with updatedItem
return {
...state,
table_data: table_data.map(e => (
e.id === updatedItem.id ? updatedItem : e
)),
};
case DELETE_ITEM:
const index = state.table_data.findIndex(e => e.id === action.item.id);
const numItems = state.table_data.length;
return {
...state,
table_data: [
// exclude index
...table_data.slice(0, index),
...table_data.slice(index+1, numItems),
]
};
default:
return state;
}
}

React-redux - state overwrites itself

I am using react-redux (for the first time). I have a component into which users put a 'startDate' and an 'endDate'. These should then be stored in the redux store, so that they persist.
I have the following action creator:
export const setDates = dates => ({
type: "SET_DATES",
payload: dates
});
The following reducer:
const dates = (state = {}, action) => {
switch (action.type) {
case "SET_DATES":
return action.payload;
default:
return state;
}
};
export default dates;
The state is set conditionally (i.e. only if the start and end dates actually make sense) like this:
handleSubmit = () => {
if (this.state.startDate <= this.state.endDate) {
store.dispatch(setDates([this.state.startDate, this.state.endDate]));
window.location = `/search/${
this.state.location
}&${this.state.startDate.format("DDMMYYYY")}&${this.state.endDate.format(
"DDMMYYYY"
)}&${this.state.guestCount}&${this.state.offset}&${this.state.count}`;
} else {
console.log("HANDLE ERROR");
}
};
The problem, according to the chrome redux dev-tools, is that when the submit is triggered, the store does indeed change to the new dates, but it then seems to be immediately overwritten to the empty state. By modifying the reducer to take state = {dates: 'foo'} as its first argument, I can get the store to persist 'dates:foo'. This suggests to me that, for some reason, the reducer is being called twice - once with an action of type "SET_DATES", which works, and then again, immediately, with an action of unknown type (confirmed by console.log-ging action.type), which causes it to return the default state.
So I'm pretty sure I know what the problem is, but I have no idea why it would do this.
I Already commented, but anyways. The problem is that you reload the page. It reloads redux, and it boots up from initial state, which is probably an empty array. Here is a great video from one of the brains behind redux.
https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage
It all boils down to subscribing to the store state changes, and saving it / loading the state back from storage of your choise.
Try changing you reducer like this
const dates = (state = {}, action) => {
switch (action.type) {
case "SET_DATES":
return Object.assign({}, state, {
action.payload
});
default:
return state;
}
};
export default dates;

Managing state of multiple list item with ID in redux

I am having multiple list item in my DOM whenever I click a list item I call the API for that particular item and store it in my Redux store and when I click another item in DOM I add it to my array in redux store.
The problem I am facing is when I click the same list item again I don't want to hit the API again I want to show data for that particular list item already stored in my redux store how should I do it?
My Reducer Code
import * as actionTypes from '../actions/actionTypes';
const initialState = {
fareRules: [],
error: false
};
const reducer = (state = initialState, action) => {
switch(action.type) {
case actionTypes.SET_FARE_RULES:
return {
...state,
fareRules: [
...state.fareRules,
{
id: action.id,
rules: action.fareRules[0][0]
}
]
}
case actionTypes.GET_FARE_RULES_FAILED:
return {
...state,
error: true
}
default:
return state;
}
}
export default reducer;
In your handler for handling a click on the item, you need to check if the fare rules for that item already exist in the store (your component needs to have access to the store).
If the fare rules for that item do no exist, add them (fire the relevant action), otherwise display them.

How to highlight multiple selection in react using redux?

I am trying to make multiple selection and highlight them. So suppose if I am displaying 5 buttons and if user clicks on a button it will be higlighted and if the user clicks on it again then it will become normal.
I am using redux store the state of my button. These button are getting created dynamically based on how many they are.
Redcuer
CurrentReducer(state = {court:{}}, action){
switch (action.type){
case 'COURT_SELECTED':{
return {...state,
court: action.payload
}
}}
Dispatcing action on onClick
this.props.dispatch(actions.selected({type:'COURT_S', payload: id}))
I had thought of storing id's in court by making it as an array or storing id with true or false in an object.
can anyone give me a simple working solution which is super easy
You can do something like this:
reduser
const selectedCourts = (state = {}, action) => {
switch (action.type) {
case 'COURT_TOGGLE': {
return {
...state,
[action.id]: !state[action.id]
};
}
}
return state;
};
action
dispatch({type: 'COURT_TOGGLE', id});
So you'll have piece of state like this:
selectedCourts: {
1: true,
2: false,
3: false,
...
}
I recommend you to use combineReducers to split your reducer into smaller parts so each subreducer would handle a simple part of your state like an array or one level object or boolean variable.
CurrentReducer.js
export default combineReducers({
selectedCourts,
...
});

Resources