how to make the if else code better, React js - javascript

I want to make the if else code I become reusable or use a switch, how do I use the switch?
this my code :
handleChange = (selectedkey) => {
this.setState({ activeKey: selectedkey })
if (selectedkey === '1') {
this.updateTabNotPay();
} else if (selectedkey === '2') {
this.updateTabNotSent();
} else if (selectedkey === '3') {
this.updateTabInDelivery();
} else if (selectedkey === '4') {
this.updateTabFinish();
} else if (selectedkey === '5') {
this.updateTabCancel();
}
};

I'd avoid switch, and instead use an object indexed by selectedkey, whose values are the associated function names:
const keyFnNames = {
'1': 'updateTabNotPay',
'2': 'updateTabNotSent',
'3': 'updateTabInDelivery',
'4': 'updateTabFinish',
'5': 'updateTabCancel'
};
// ...
handleChange = (selectedkey) => {
this.setState({ activeKey: selectedkey })
const fnName = keyFnNames[selectedKey];
if (fnName) {
this[fnName]();
}
};
If you know that selectedKey will always have a corresponding function, then you can levae out the if (fnName) check.
Using switch instead would be unnecessarily verbose and more error-prone, IMO.

i suppose something like this could work ?
handleChange = (selectkey) => {
this.state({ activeKey: selectedkey })
switch(selectedkey){
case 1:
this.updateTabNotPay();
break;
case 2:
this.updateTabNotSent();
break;
case 3:
this.updateTabInDelivery();
break;
case 4:
this.updateTabFinish();
break;
case 5:
this.updateTabCancel();
break;
default:
console.log("error");
}
}
strong text

Related

Redux state entry hashing

I am trying to store a collection of data in my redux store, hashed by id field.
My reducer looks like:
// The initial state of the App
export const initialState = {
events: {},
loading: false,
saving: false,
error: false
};
const eventReducer = (state = initialState, action) =>
produce(state, draft => {
switch (action.type) {
case LOAD_EVENT:
draft.loading = true;
draft.error = false;
break;
case LOAD_EVENT_SUCCESS:
draft.loading = false;
draft.events = {
...state.events,
[action.id]: action.event
};
break;
case LOAD_EVENT_ERROR:
draft.loading = false;
draft.error = action.error;
break;
case LOAD_PENDING:
draft.loading = true;
draft.error = false;
break;
case LOAD_PENDING_SUCCESS:
draft.loading = false;
draft.events = {
...state.events,
...action.events.map(entry => {
return { [entry['id']]: entry };
})
};
break;
case LOAD_PENDING_ERROR:
draft.error = action.error;
draft.loading = false;
break;
case LOAD_UPCOMING:
draft.loading = true;
draft.error = false;
break;
case LOAD_UPCOMING_SUCCESS:
draft.loading = false;
draft.events = {
...state.events,
...action.events.map(entry => {
return { [entry['id']]: entry };
})
};
break;
case LOAD_UPCOMING_ERROR:
draft.error = action.error;
draft.loading = false;
break;
case LOAD_PREVIOUS:
draft.loading = true;
draft.error = false;
break;
case LOAD_PREVIOUS_SUCCESS:
draft.loading = false;
draft.events = {
...state.events,
...action.events.map(entry => {
return { [entry['id']]: entry };
})
};
break;
case LOAD_PREVIOUS_ERROR:
draft.error = action.error;
draft.loading = false;
break;
}
});
Where action.event would look like {id: 12, name: 'Test', ...} and action.events would be an array like [{id: 12, name: 'Test', ...}, {id: 15, name: 'Another test', ...}].
However, when I load events as a result of successful LOAD_PENDING_SUCCESS action, the state has: {events: {0: {12, {id: 12, name: 'Test', ...}}}, {1: {15: {id: 15, name: 'Another test', ...}}}}
I want my events to have the event id as the key so when I do = {...events, ...newEvents}, if events property of the state object has data with the same id as records from newEvents, events objects get replaced by the entries from newEvents.
You can try like this:
case LOAD_PENDING_SUCCESS:
draft.loading = false;
draft.events = {
...state.events,
...action.events.reduce((acc, val) => {
return { ...acc, [val.id]: val };
}, {})
};
break;
Or, for normalization of data, you can use normalizr library. It is super useful.

change node icon using fancytree.js

I am using fancytree.js for treeview and I have a callback on the tree:
$("#tree").fancytree({
source: {url: "/" + appPath + "/pathosadmin?treepages=true"},
postProcess: function (event, data) {
data.result = convertData(data.response, true);
},
init: function (event, data) {
var root = $("#tree").fancytree("getRootNode");
root.sortChildren(function (a, b) {
return treeSort(a, b);
}, true);
},
icon: function (event, data) {
switch (data.node.data.NODE_TYPE) {
case 1: //page
if (data.node.data.STARTPAGE == 0) {
return "fancytree_page_icon";
} else if (data.node.data.STARTPAGE == 1) {
_this.startPageNode = data.node;
return "fancytree_startpage_icon";
}
case 2: //group
return "fancytree_group_icon";
case 3: //level
if (data.node.data.LEVELID) {
switch (data.node.data.LEVELID) {
case 1:
return "fancytree_level_1_icon";
case 2:
return "fancytree_level_2_icon";
case 3:
return "fancytree_level_3_icon";
case 4:
return "fancytree_level_4_icon";
case 5:
return "fancytree_level_5_icon";
}
} else {
return "fancytree_location_icon";
}
}
},
extensions:
Now I want to also change the icons on runtime. Sadly
if (_this.startPageNode) {
_this.startPageNode.icon = "fancytree_page_icon";
_this.startPageNode.renderTitle();
}
activeNode.icon = "fancytree_startpage_icon";
activeNode.render();
_this.startPageNode = activeNode;
doesnt work. Any hints on how to tackle that problem. The node.icon attribute is always undefined and even if i set it (+render the node) it doesnt show.
renderTitle() calls icon function, so only way I found to change icon dynamically is to put some attribute on node
activeNode.state = 'clicked';
activeNode.renderTitle();
and then put extra handling login in icon function on tree:
var state = data.node.state;
if (state) {
switch (state) {
case "clicked": return "glyphicon glyphicon-ban-circle"
return;
case "completed": return "glyphicon glyphicon-ok-circle"
return;
case "removed": return "glyphicon glyphicon-remove-circle"
return;
default:
return "glyphicon glyphicon-remove-circle"
break;
}
}

Javascript multiple decisions in switch case

I have difficulty with running a code which checks two criteria in switch case as this code prints 'unknown' since in javascript
['police',false]!=['police',false]
Is there any way to implement this code using switch-case rather than nested ifs?
var option='police';
var urgent=false;
switch([option,urgent])
{
case ['police',true]:
console.log('police,true');
call_police_urgent();
break;
case ['police',false]:
console.log('police,false');
call_police();
break;
case ['hospital',true]:
console.log('hospital,true');
call_hospital_urgent();
break;
case ['hospital',false]:
console.log('hospital,false');
call_hospital();
break;
case ['firestation',true]:
console.log('firestation,true');
call_firestation_urgent();
break;
case ['firestation',false]:
console.log('firestation,false');
call_firestation();
break;
default:
console.log('unknown');
}
Your code doesn't work because one array literal is never equal to another even if they look the same. There are many ways to solve that, but most of them boil down to converting arrays to something one can compare, e.g. strings:
let str = (...args) => JSON.stringify(args);
switch (str(option, urgent)) {
case str('police', false):
console.log('police,false');
break;
case str('hospital', true):
console.log('hospital,true');
break;
default:
console.log('unknown');
}
This works for your simple case, but not in general, because not everything can be stringified.
You can convert an array of options to string:
var option='police';
var urgent=false;
switch([option,urgent].join())
{
case 'police,true':
console.log('police,true');
break;
case 'police,false':
console.log('police,false');
break;
case 'hospital,true':
console.log('hospital,true');
break;
case 'hospital,false':
console.log('hospital,false');
break;
case 'firestation,true':
console.log('firestation,true');
break;
case 'firestation,false':
console.log('firestation,false');
break;
default:
console.log('unknown');
}
i don't know what you are trying to do, but your above code javascript engines and runtime environments with yell at you.
and secondly [] literal can and will never be equal to another [] literal
choose in between this two
var option='police';
var urgent=false;
function first_switch(option,urgent) {
switch(option) {
case "police":
if ( urgent )
console.log('police,true');
else
console.log('police,false');
break;
case "hospital":
if ( urgent )
console.log('hospital,true');
else
console.log('hospital,false');
break;
case "firestation":
if ( urgent )
console.log('firestation,true');
else
console.log('firestation,false');
break;
default:
console.log('unknown');
}
}
function second_switch(option,urgent) {
if ( urgent ) {
switch(option) {
case "police":
case "hospital":
case "firestation":
console.log(`${option}`, "true");
break;
default:
console.log('unknown');
}
return ;
}
switch(option) {
case "police":
case "hospital":
case "firestation":
console.log(`${option}`, "false");
break;
default:
console.log('unknown');
}
}
first_switch(option,urgent);
first_switch(option, true);
second_switch(option, urgent);
second_switch(option, true);
We can create the same funtionality without using switch cases. We could create a lookup table like:
var emergencyLookupTable = {
police: [{
case: true,
fn: call_police_urgent
},
{
case: false,
fn: call_police
}
],
hospital: [{
case: true,
fn: call_hospital_urgent
},
{
case: false,
fn: call_firestation_urgent
}
],
firestation: [{
case: true,
fn: call_firestation_urgent
},
{
case: false,
fn: call_firestation
}
]
}
And pass this object into emergency which is looking for the correct cases.
function emergency(lookup, option, urgent) {
if (lookup[option]) {
lookup[option]
.filter(function(obj) {
return obj.case === urgent
})
.forEach(function(obj) {
obj.fn()
})
} else {
console.log('unknown')
}
}
emergency(emergencyLookupTable, 'police', true)
Working Example
var emergencyLookupTable = {
police: [{
case: true,
fn: call_police_urgent
},
{
case: true,
fn: call_police_urgent2
},
{
case: false,
fn: call_police
}
],
hospital: [],
firestation: []
}
function emergency(lookup, option, urgent) {
if (lookup[option]) {
lookup[option]
.filter(function(obj) {
return obj.case === urgent
})
.forEach(function(obj) {
obj.fn()
})
} else {
console.log('unknown')
}
}
function call_police_urgent() {
console.log('call the police!')
}
function call_police_urgent2() {
console.log('call the police again!')
}
function call_police() {
console.log('call the police..')
}
emergency(emergencyLookupTable, 'police', true)
emergency(emergencyLookupTable, 'police', false)

prevent duplicate objects being added to state react redux

I have a question regarding preventing duplicates from being added to my redux store.
It should be straight forward but for some reason nothing I try is working.
export const eventReducer = (state = [], action) => {
switch(action.type) {
case "ADD_EVENT":
return [...state, action.event].filter(ev => {
if(ev.event_id !== action.event.event_id){
return ev;
}
});
default:
return state;
}
};
The action looks something like the below:
{
type: "ADD_EVENT",
event: { event_id: 1, name: "Chelsea v Arsenal" }
}
The issue is that on occasions the API I am working with is sending over identical messages through a websocket, which means that two identical events are getting added to my store.
I have taken many approaches but cannot figure out how to get this to work. I have tried many SO answers,
Why your code is failing?
Code:
return [...state, action.event].filter(ev => {
if(ev.event_id !== action.event.event_id){
return ev;
}
});
Because first you are adding the new element then filtering the same element, by this way it will never add the new value in the reducer state.
Solution:
Use #array.findIndex to check whether item already exist in array or not if not then only add the element otherwise return the same state.
Write it like this:
case "ADD_EVENT":
let index = state.findIndex(el => el.event_id == action.event.event_id);
if(index == -1)
return [...state, action.event];
return state;
You can use Array.prototype.find().
Example (Not tested)
const eventExists = (events, event) => {
return evets.find((e) => e.event_id === event.event_id);
}
export const eventReducer = (state = [], action) = > {
switch (action.type) {
case "ADD_EVENT":
if (eventExists(state, action.event)) {
return state;
} else {
return [...state, action.event];
}
default:
return state;
}
};
Update (#CodingIntrigue's comment)
You can also use Array.prototype.some() for a better approach
const eventExists = (events, event) => {
return evets.some((e) => e.event_id === event.event_id);
}
export const eventReducer = (state = [], action) = > {
switch (action.type) {
case "ADD_EVENT":
if (eventExists(state, action.event)) {
return state;
} else {
return [...state, action.event];
}
default:
return state;
}
};
Solution:
const eventReducer = ( state = [], action ) => {
switch (action.type) {
case 'ADD_EVENT':
return state.some(( { event_id } ) => event_id === action.event.event_id)
? state
: [...state, action.event];
default:
return state;
}
};
Test:
const state1 = eventReducer([], {
type: 'ADD_EVENT',
event: { event_id: 1, name: 'Chelsea v Arsenal' }
});
const state2 = eventReducer(state1, {
type: 'ADD_EVENT',
event: { event_id: 2, name: 'Chelsea v Manchester' }
});
const state3 = eventReducer(state2, {
type: 'ADD_EVENT',
event: { event_id: 1, name: 'Chelsea v Arsenal' }
});
console.log(state1, state2, state3);
You can something like this, for the logic part to ensure you don't get the same entry twice.
const x = filter.arrayOfData(item => item.event_id !== EVENT_FROM_SOCKET);
if (x.length === 0) {
// dispatch action here
} else {
// ignore and do nothing
}
You need to be careful when using Arrays in reducers. You are essentially adding more items to the list when you call:
[...state, action.event]
If you instead use a map then you can prevent duplicates
const events = { ...state.events }
events[action.event.event_id] = action.event.name]
{...state, events }
If duplicate exist in previous state then we should return same state else update the state
case "ADDPREVIEW":
let index = state.preview.findIndex(dup => dup.id == action.payload.id);
return {
...state,
preview: index == -1 ? [...state.preview,action.payload]:[...state.preview]
};

setState not working with Switch block

I'm trying to build a little chat bot, and I seem to be nearing completion if it were not for this bug. The issue seems to be that my switch statement isn't handling the setState properly.
Uquestion extends React.Component {
constructor(props) {
super(props);
this.state = {
text: this.props.text,
response: "Here is the answer"
}
this.handleChange = this.handleChange.bind(this)
this.key = this.key.bind(this)
this.fetchResponse = this.fetchResponse.bind(this)
}
handleChange(event) {
this.setState({
question: event.target.value
})
}
fetchResponse() {
switch(this.state.searchKey) {
case "BBQ":
this.setState({
response:"Texas BBQ"
})
break;
case "book":
this.setState({
response:"It's close, but probably The Night in Question by Tobias Wolff."
})
break;
case "restaurant":
this.setState({
response:"Andaman, a little Thai spot in Denton, Texas."
})
break;
case "work":
this.setState({
response:"Lots of this and lots of that."
})
break;
case "upbringing":
this.setState({
response:"Texas thunderstorms over endless plains."
})
break;
case "future":
this.setState({
response:"I hope to work on meaningful applications and write meaningful narratives"
})
break;
case "fun":
this.setState({
response:"When the moon is full, I write by candle light."
})
break;
default:
this.setState({
response:"Um, what?"
})
}
}
//this function sets a key that I will later use to fetch a response to the user's question.
key() {
var question=this.state.question;
var questionUpper=question.toUpperCase();
// the is not -1 determines if the phrase appears anywhere in the question.
if(questionUpper.search("FAVORITE FOOD")!==-1) {
this.setState({
searchKey:"BBQ"
}, this.fetchResponse())
}
else if(questionUpper.search("FAVORITE BOOK")!==-1) {
this.setState({
searchKey:"Book"
}, this.fetchResponse())
}
else if(questionUpper.search("FAVORITE RESTAURANT")!==-1) {
this.setState({
searchKey:"Restaurant"
},this.fetchResponse())
}
else if(questionUpper.search("WORK EXPERIENCE")!==-1) {
this.setState({
searchKey:"work"
},this.fetchResponse())
}
else if(questionUpper.search("GROWING UP")!==-1) {
this.setState({
searchKey:"upbringing"
},this.fetchResponse())
}
else if(questionUpper.search("FAVORITE AUTHOR")!==-1) {
this.setState({
searchKey:"author"
},this.fetchResponse())
}
else if(questionUpper.search("FUTURE")!==-1) {
this.setState({
searchKey:"future"
},this.fetchResponse())
}
else if (questionUpper.search("FOR FUN")!==-1) {
this.setState({
searchKey:"fun"
},this.fetchResponse())
}
else {
this.setState({
searchKey:"default"
}, this.fetchResponse())
}
}
render() {
return (
<div>
<p> {this.state.response} </p>
<textarea onChange = {this.handleChange} className="q"> {this.props.text} </textarea>
<button className="a" onClick={this.key}>Ask!</button>
</div>
);
}
}
ReactDOM.render(<Uquestion text="Type Question Here."/>, document.getElementById("content"))
You are passing wrong callback in setState function. And in fetchResponse you've wrote some wrong cases. I've corrected your mistakes, you can see on working example in Codepen
wrong:
this.setState({
searchKey: "book"
}, this.fetchResponse())
correct:
this.setState({
searchKey: "book"
}, this.fetchResponse)
you can read react source code
ReactComponent.prototype.setState = function (partialState, callback){
!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : _prodInvariant('85') : void 0;
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
enqueueCallback: function (publicInstance, callback, callerName) {
ReactUpdateQueue.validateCallback(callback, callerName);
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance);
if (!internalInstance) {
return null;
}
if (internalInstance._pendingCallbacks) {
internalInstance._pendingCallbacks.push(callback);
} else {
internalInstance._pendingCallbacks = [callback];
}
enqueueUpdate(internalInstance);
}
function enqueueUpdate(internalInstance) {
ReactUpdates.enqueueUpdate(internalInstance);
}
so, I think you the callback is like this:
this.setState({
searchKey:"BBQ"
}, this.fetchResponse)

Categories