I spend a day for investigating this case, but seen no hope.
const Tests = (state = INIT_STATE, action) => {
switch (action.type) {
case GET_TEST_DETAIL:
return {
...state,
test: {},
error: {},
updatingTest: true,
}
case GET_TEST_DETAIL_SUCCESS:
const test = action.payload
console.log(action.payload.shortName)//has data
test["shortName2"] = action.payload.shortName//has data
test["shortName"] = action.payload.shortName//empty string
console.log(test)
return {
...state,
test: test,
updatingTest: false,
}
There is the picture captured when I console.log in firefox, and Edge:
There's nothing wrong.
const action = {
payload: {
shortName: 'I am a shortname'
}
}
const test = action.payload
console.log(action.payload.shortName)//has data
test["shortName2"] = action.payload.shortName//has data
test["shortName"] = action.payload.shortName//empty string
console.log(test)
Related
it is a common pattern to use the switch statement with useReducer hook to handle complex states, but the complexity rule thrown error if the number of cases is too high. what are the alternatives to refactor this code to satisfy this rule?
export type SearchState = {
search: string;
markets: Market[];
};
type SearchAction =
| { type: SearchActionKind.UpdateSearch; search: string }
| { type: SearchActionKind.LoadInitialMarkets; markets: Market[] };
const searchReducer = (prevState: SearchState, action: SearchAction): SearchState => {
switch (action.type) {
case UpdateSearch:
return { ...prevState, search: action.search };
case LoadInitialMarkets:
return { ...prevState, markets: action.markets };
// ... many other cases
default:
return prevState;
}
};
Could you use a map to reduce the switch statement?
const map = {};
map[UpdateSearch] = 'search';
map[LoadInitialMarkets] = 'markets';
if (map.hasOwnProperty(action.type)) {
const key = map[action.type];
const result = { ...prevState };
result[key] = action[key];
return result;
}
switch (action.type) {
// ... the complicated cases
default:
return prevState;
}
I'm working on my first solo ReactJS/Redux project and things were going well until I got to a point where I'm using an object in the Redux store that is always supposed to be a single object. When I copy the object from one part of the store (one element of the sources key) to another (the selectedItems key) that object is being stored as an array of length 1, which isn't the data I'm passing in (it's just a single object). I could live with this and just read out of that store variable as an array and just use element 0 except that when I call another method in the reducer to replace that variable in the store, that method stores the new data as a single object! My preference would be to have everything store a single object but I can't figure out how to do that. Anyway, here's some of the reducer code:
const initialState = {
sources: [
{
id: 1,
mfg: 'GE',
system: 'Smart bed',
model: '01',
name: 'GE smart bed'
},
{
id: 2,
mfg: 'IBM',
system: 'Patient monitor',
model: '03',
name: 'IBM patient monitor'
}
],
error: null,
loading: false,
purchased: false,
selectedItem: {}
};
// This is called when a user selects one of sources in the UI
// the Id of the selected sources object is passed in as action.id
// This method creates an array in state.selectedItem
const alertSourceSelect = ( state, action ) => {
let selectedItem = state.sources.filter(function (item) {
return item.id === action.id;
});
if (!selectedItem) selectedItem = {};
return {...state, selectedItem: selectedItem};
};
// When someone edits the selected source, this takes the field name and new value to
// replace in the selected source object and does so. Those values are stored in
// action.field and action.value . However, when the selected source object is updated
// it is updated as a single object and not as an array.
const selectedSourceEdit = ( state, action ) => {
return {
...state,
selectedItem: updateObject(state.selectedItem[0], { [action.field] : action.value })
};
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case actionTypes.ALERT_SOURCE_SELECT: return alertSourceSelect( state, action );
case actionTypes.ALERT_SELECTED_SOURCE_EDIT: return selectedSourceEdit( state, action );
default: return state;
}
Here is the updateObject method (sorry I left it out):
export const updateObject = (oldObject, updatedProperties) => {
return {
...oldObject,
...updatedProperties
}
};
Issue : updateObject is returning object and not array,and you are maintaining selectedItem as an array not object
export const updateObject = (oldObject, updatedProperties) => {
return {
...oldObject,
...updatedProperties
}
};
Solution :
Either return array from updateObject :
export const updateObject = (oldObject, updatedProperties) => {
return [{
...oldObject,
...updatedProperties
}]
};
OR make array of returned object
const selectedSourceEdit = ( state, action ) => {
return {
...state,
selectedItem: [updateObject(state.selectedItem[0], { [action.field] : action.value })]
};
};
Here is my state
const initState = [
{
id: 1,
criteria: [],
isInclusion: true,
},
{
id: 2,
criteria: [],
isInclusion: true,
},
];
I am trying to add a new object into criteria array with my dispatch
dispatch(
addCriteria({
id: item.id,
type: item.type,
groupId: 1,
})
);
in the reducer I do the following but it doesnt add to an array of an existing group but instead, it adds as a new object to the array with that criteria added in it.
const addReducer = (state = initState, action) => {
switch (action.type) {
case QUERYGROUPS.ADD_CRITERIA: {
const newCriteria = {
id: action.payload.id,
type: action.payload.type,
};
const newState = [
...state,
state.map(group =>
group.id === action.payload.groupId
? {
...group,
criteria: newCriteria,
}
: group
),
];
return newState;
}
}
};
You are adding all items to the state object (also the one you want to modify) with ...state and than you map over it again. This will not work.
You should change your state object to be an object to access the items by reference and not index and use the id as access. This will also be faster(thanks #Yash Joshi ):
const initState = {
1: {
criteria: [],
isInclusion: true,
},
2: {
criteria: [],
isInclusion: true,
},
};
This will let you access and update the state more easily and easier to stay immutable.
This will let you update it like this:
case QUERYGROUPS.ADD_CRITERIA: {
const newCriteria = {
id: action.payload.id,
type: action.payload.type,
};
const newState = {
...state,
[action.payload.groupId]: {
...state[action.payload.groupId],
criteria: [
...state[action.payload.groupId].criteria,
newCriteria
],
}
};
return newState;
To add a new item to it:
const newState = {
...state,
[action.payload.groupId]: {
isInclusion: false,
criteria: [ ],
}
};
Hope this helps. Happy coding.
Try spread operator (es6):
return [
...state,
newCriteria,
]
This will return a new array with the newCriteria object on it.
Here is how I'd do it:
const newCriteria = {
id: action.payload.id,
type: action.payload.type,
};
const newState = state.map(gr => {
if (gr.id !== action.payload.groupId) {
return gr;
}
return {
...gr,
criteria: [...gr.criteria, newCriteria];
}
});
I think you should follow Domino987 approach it will be faster. But if you still wish to continue with your approach. You can try this:
const newState = state.map(item => item.id === newItem.id ? ({ ...item, ...newItem }) : item );
return newState;
Hope this Helps!
How do i write this inside of an reducer to change the state?
doc = {
id:"zf123ada123ad",
name:"examp",
subdoc:{
name:"subdoc examp",
subsubdoc:[{
id:"zcgsdf123zaar21",
subsubsubdoc:[{
id:"af2317bh123",
value: "heyhey" //this value I want to update
}]
}]
}
}
let's say i have an reducer that looks like this
The action.payload look something like this
{
theInputId1: "someId",
theInputId2: "anotherId",
theInputValue: "someValue"
}
export function updateSubSubSubDoc(state = {}, action){
switch(action.type){
case 'UPDATE_THE_SUBSUBSUB':
return {
state.doc.subdoc.subsubdoc.find(x => x.id ==
theInputId1).subsubsubdoc.find(x => x.id == theInputId2).value = theInputValue // just example code for you to understand where i'm going.
}
default:
return state
}
}
What I want to do it update one subsubsub doc in a state that is current
With ES6, this is one way that you could do that:
const initialState = { doc: { subdoc: { subsubdoc: {} } } };
export function doc(state = initialState, action) {
switch (action.type) {
case 'UPDATE_THE_SUBSUBSUB':
const subsubdocIdx = state.doc.subdoc.
subsubdoc.find(s => s.id == action.theInputId1);
const subsubdoc = state.doc.subdoc.subsubdoc[subsubdocIdx];
const subsubsubdocIdx = state.doc.subdoc.
subsubdoc[subsubdocIdx].
subsubsubdoc.find(s => s.id == action.theInputId2);
const subsubsubdoc = state.doc.subdoc.
subsubdoc[subsubdocIdx].
subsubsubdoc[subsubsubdocIdx];
return {
...state,
doc: {
...state.doc,
subdoc: {
...state.doc.subdoc,
subsubdoc: [
...state.doc.subdoc.subsubdoc.slice(0, subsubdocIdx),
{
...subsubdoc,
subsubsubdoc: [
...subsubdoc.slice(0, subsubsubdocIdx),
{
...subsubsubdoc,
value: action.theInputValue,
},
...subsubdoc.subsubsubdoc.slice(subsubsubdocIdx + 1, subsubdoc.subsubsubdoc.length - 1),
],
},
...state.doc.subdoc.subsubdoc.slice(subsubdocIdx + 1, state.doc.subdoc.subsubdoc.length - 1),
]
}
}
}
default:
return state;
}
}
(I haven’t tested this code.)
This is nested the same level as in your example, but you might consider using something like combineReducers to make this a little easier to manage. This is also presupposing you have other actions that create the document chain along the way, and you know these documents exist.
Here's an example how you might be able to do it with combineReducers:
function doc(state = {}, action) {
}
function subdoc(state = {}, action) {
}
function subsubdoc(state = [], action) {
}
function subsubsubdoc(state = [], action) {
switch (action.type) {
case 'UPDATE_THE_SUBSUBSUB':
const idx = state.find(s => s.id == action.theInputId2);
return [
...state.slice(0, idx),
{
...state[idx],
value: action.theInputValue,
},
...state.slice(idx + 1),
];
default:
return state;
}
}
export default combineReducers({
doc,
subdoc,
subsubdoc,
subsubsubdoc,
});
In this example, you don't need action.theInputId1, but you would need to store some reference in the data from the subsubdoc to the subsubsubdoc so that when you're rendering, you can piece it back together. Same with all of the other layers.
i am creating a file system App using react-redux and am new to this.
i just want to append the latest data into previous data.
here is my code snippet
action.js
export function getFolderList(url){
const local_url_LOW = isLocal ? lowJSON : url + '?fileFidelity=LOW';
const lowRequest = axios.get(local_url_LOW);
return{
type: GET_FOLDER_LIST,
payload: lowRequest
};
}
reducer.js
export default function (state = INITIAL_STATE, action) {
switch (action.type) {
case GET_FOLDER_LIST:
let data = action.payload.data.Files.File
folderData = Array.isArray(data) ? data : [data];
if (folderData.length) {
for (var i = 0; i < folderData.length; i++) {
lst.push({
id: folderData[i].oid,
name: folderData[i].location,
type: folderData[i].type,
childCount: folderData[i].childCount,
createdDate: folderData[i].createdDate,
lastModifiedDate: folderData[i].lastModifiedDate,
location: folderData[i].location
});
}
return lst;
}
break;
}
return state;
}
so i want to return data like .. state.chlidFiles : lst
so can anyone tell me hoe to do this.
currently when my returning lst array it is creating new state with the previous and the lst arrya, but i want to add this new lst array in previous state's childFiles(or you can say to a specific property)
i have used redux-promise for promises.
I am shooting a blind suggestion here. I would use redux-thunk for async operation, then I would dispatch this and use in my reducer.
action
const getFolderList = (url) =>
( dispatch) => {
const local_url_LOW = isLocal ? lowJSON : url + '?fileFidelity=LOW';
const lowRequest = await axios.get(local_url_LOW);
const data = lowRequest.data.Files.File;
const folderData = Array.isArray(data) ? data : [data];
const payload = folderData.map( file => ( {
id: file.oid,
name: file.location,
type: file.type,
childCount: file.childCount,
createdDate: file.createdDate,
lastModifiedDate: file.lastModifiedDate,
location: file.location,
} ) );
dispatch( {
type: GET_FOLDER_LIST,
payload,
} )
}
reducer
export default function ( state = INITIAL_STATE, action ) {
switch ( action.type ) {
case GET_FOLDER_LIST:
return { ...state, childFiles: [ ...state.childFiles, ...action.payload ] };
default:
return state;
}
}