avoid cyclomatic complexity in switch statements(useReducer) - javascript

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;
}

Related

One of attribute lost data when assign javascript object

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)

How to refactor multipler if statements into cleaner and easier to read code in javascript?

I have multiple if statements in a function like this :
const handleCat = () => {
if (mainCat === 'car') {
return carCat;
}
if (mainCat === 'mobile') {
return mobileCat;
}
if (mainCat === 'estate') {
return estateCat;
}
if (mainCat === 'other') {
return otherCat;
}
};
All the cat's are arrays with objects . I was wondering how can I refactor this code into much more cleaner and easier to read code ? How many ways are there to refactor multiple if statements in javascript ?
One way which I would recommend will be to use an object type.
const genericCat = {
car : carCat,
mobile : mobileCat,
estate:estateCat,
other : otherCat
}
handleCat = (mainCat)=>{
return(generiCat[mainCat])
}
this approch also saves you from updating your code from more then one place if types of cat are increased.This is like using Enums in Java but with objects.
Using a switch statement:
const handleCat = () => {
switch (mainCat) {
case 'car':
return carCat;
case 'mobile':
return mobileCat;
case 'estate':
return estateCat;
case 'other':
return otherCat;
default:
break;
}
};
A switch statement is an option
const handleCat = (mainCat) => {
switch(mainCat) {
case "car":
return "carCat";
case "mobile":
return "mobileCat";
case "estate":
return "estateCat";
case "other":
return "otherCat";
default:
return "fallbackCat";
}
};
const first = handleCat("car");
const second = handleCat();
console.log(first);
console.log(second);
You could also save the options in an object and return them based on their key.
const handleCat = (mainCat) => {
const fallback = "fallbackCat";
const catMap = {
car: "carCat",
mobile: "mobileCat",
estate: "estateCat",
other: "otherCat",
};
return catMap[mainCat] || fallback;
};
const first = handleCat("car");
const second = handleCat();
console.log(first);
console.log(second);
You can use a switch statement:
var mainCat = 'car';
const handleCat = () => {
switch(mainCat) {
case 'car':
return carCat;
break;
case 'mobile:
return mobileCat;
break;
case 'estate'
return estateCat;
break;
default:
return otherCat;
}
}

Query inside reducer ? redux

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.

How to append updated data in previous state in react-redux?

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;
}
}

How to make this piece of code look better

This is one of my redux reducers and I feel it looks very ugly. Is it possible to improve it?
The goal that I want to achieve is very simple:
If I already have this item in my current state, increase the quantity by 1,
otherwise add this item to state.
function globalReducer(state = initialState, action) {
switch (action.type) {
case ADD_TO_CART: {
let { item } = action;
if (state.getIn(['sideCart', 'orderItems', item.id])) {
item.quantity = state.getIn(['sideCart', 'orderItems', item.id]).get('quantity') + 1;
} else {
item.quantity = 1;
}
item = fromJS(item);
const newState = state.setIn(['sideCart', 'orderItems', item.get('id')], item);
return newState;
}
default:
return state;
}
}
The state should look like this:
sideCart: {
orderItems: {
1: {
id: 'orderItems-1',
name: 'AI Brown\'s BBQ Fillet of Beef with Brown Mushroom Brandy Sauce',
quantity: 10,
price: 12,
subitems: ['0', '1', '2'],
instruction: 'No rosemary for beef',
},
2: {
id: 'orderItems-2',
name: 'AI Brown\'s BBQ Fillet',
quantity: 10,
price: 14,
subitems: ['0', '1', '2'],
instruction: 'No rosemary for beef',
},
},
}
This is how I would enhance it syntactically:
const reduceCart = (state, action) => {
let { item } = action;
const stateIn = state.getIn(['sideCart', 'orderItems', item.id]);
item.quantity = stateIn
? stateIn + 1
: 1;
item = fromJS(item);
return state.setIn(['sideCart', 'orderItems', item.get('id')], item);
};
const globalReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_TO_CART: return reduceCart(state, action);
default: return state;
}
};
I found the same complexity when using immutable.js to handle deeply nested objects. I have made a lightweight immutable helper: ImmutableAssign that allows you to continue working with plain JS objects, which will simplify your operations.
In the following example, it expects state and action to be plain JS objects, and it will return you a new state as plain JS object:
function globalReducer(state = initialState, action) {
switch (action.type) {
case ADD_TO_CART: return addCart(state, action);
default: return state;
}
}
function addCart(state, action) {
let { item } = action;
return iassign(state,
function(state, context) {
return state.sideCart.orderItems[context.item.id]
},
function(selectedItem) {
item.quantity = selectedItem.quantity ? selectedItem.quantity + 1 : 1;
return item;
},
{ item: item });
}
// The first parameter is a function that return the
// property you need to modify in your state.
// This function must be **pure function**, therefore "item"
// need to be passed in via the context parameter.
//
// The second parameter is a function that modify selected
// part of your state, it doesn't need to be pure, therefore
// you can access "item" directly
//
// The third parameter is the context used in the first
// function (pure function)

Categories

Resources