Received NaN in Reducer in Redux/React Js - redux

I'm trying to make a task which is every click will "INCREMENT" + 1 item number in the cart. But it does not work as expected and I got this error instead:
index.js:1 Warning: Received NaN for the children attribute. If this is expected, cast the value to a string.
My code is here
const initialState = {
counter : 0,
cartData : []
};
function cartNumber(state = initialState, action) {
switch(action.type){
case "INCREMENT" :
var index = state.cartData.findIndex(el => el.name === action.newData.name);
var cartNumber = Number(state.counter);
if (index > -1) {
return {
...state,
cartData : state.cartData.map((el) => el.name === action.newData.name ? {...el, quantity : Number(el.quantity + 1), price : Number(el.price + el.total) } : el),
counter : Number(state.cartData.map((el) => Number(el.quantity))) + 1 // NOTE : **I think this line is the error, but i dont know how to fix it**
}
} else {
return {
...state, counter : Number(cartNumber + 1),
cartData : state.cartData.concat(action.newData)
}
}
break;
case "DECREMENT" :
if (state.cartData.quantity < 1) {
return {
...state,
cartData : state.cartData.map((el) =>
el.name === action.decrementData ? {...el, quantity: el.quantity !== 1 ? el.quantity - 1 : 1, price : el.price !== el.total ? el.price - el.total : el.price } : el)
}
} else {
return {
...state,
cartData : state.cartData.filter(el => el.name !== action.decrementData ),
counter : state.cartData.map((el) => el.name === action.decrementData ? state.counter - el.quantity : el)
}
}
default:
return state;
}
return state
}
export default cartNumber;
I have been trying to fix it by convert all the quanlity to number but it still not working. It is originally a array because i took from the cartData array that is why i converted it.

You might be right here:
counter : Number(state.cartData.map((el) => Number(el.quantity))) + 1 // NOTE :
**I think this line is the error, but i dont know how to fix it**
The state.cartData.map((el) => Number(el.quantity)) return an array. Number([]) is 0, but Number([any_item]) will return NaN

cartData.map will return an array, you use Number and passing an array in. It will return NaN

Related

Redux reducer state not updating

import types from "../actions/types";
export default function(state = null, action) {
switch (action.type) {
case types.fetchCartProducts:
return action.payload || false;
case types.modifyCart:
debugger;
switch (action.payload.operation) {
case "subtract":
const index = action.payload.index;
let isSingleCount = state[index] === 1;
let chosenIds = state;
if (isSingleCount) {
chosenIds = chosenIds.filter(index => index != index);
} else {
[
...chosenIds.slice(0, index),
{ ...chosenIds[index], count: chosenIds[index].count - 1 },
...chosenIds.slice(index + 1)
];
}
return (
chosenIds
)
}
default:
return state;
}
}
{
"Products": [
{
index: 1,
name: "Shirt",
price: 1.9,
count: 2
},
{
index: 2,
name: "Jeans",
price: 1.9,
count: 2
}
]
}
I have a react component showing cart products. Each product in the cart is a seperate div and having + and - buttons to increase, decrease the no of that product. On - click I want to decrease the quantity and also if count is reduced to 0 I want to remove this product as well from my redux state.
Now I have my reducer where first I am checking if the count is 1 then removing the product itself else reducing the count only. I am returning the state but its not updating the DOM
Can anyone help in this am I doing something wrong in returning state.
Thanks
It looks like you are directly manipulating the state, which will cause problems in React. Instead of let chosenIds = state;, you should copy the state, let chosenIds = Object.assign({}, state);. Then you can manipulate chosenIds as you wish.
Looks like you forgot to include a assignment statement in the else block.
} else {
chosenIds = [
...chosenIds.slice(0, index),
{ ...chosenIds[index], count: chosenIds[index].count - 1 },
...chosenIds.slice(index + 1)
];
}
Instead of this complicated operation, you could use array.map to update a single item in the array.
chosenIds = state.map(item => item.index === index ? {...item, count: item.count - 1} : item)

fetchProvidersForEmail returning undefined

I'm trying to check if an email exists by using fetchProvidersForEmail, however the function that I've written keeps returning undefined.
var emailExists = (emailAddress) => {
firebase.auth().fetchProvidersForEmail(emailAddress)
.then((providers) => {
return providers.length > 0;
});
};
In addition to this, I have also tried
var emailExists = (emailAddress) => {
var exists = false;
firebase.auth().fetchProvidersForEmail(emailAddress)
.then((providers) => {
exists = providers.length > 0;
});
return exists;
};
When replacing return ... with console.log(providers.length > 0) the value that I expect is returned. What am I doing wrong here?
You have to do this:
var emailExists = (emailAddress) => {
return firebase.auth().fetchProvidersForEmail(emailAddress)
.then((providers) => {
return providers.length > 0;
}); };
firebase.auth().fetchProvidersForEmail returns a promise with the boolean of whether providers.length > 0 or not.
But in your emailExists function, you didn't return the promise. So undefined is returned.

Issue with observable fork join

Hi I have 3 tables of which, each one is child of another. I wrote a method to fetch from sqllite db as follows
public downloadFromOfflineDB(db,testSO){
var observableBatch = [];
observableBatch.push(db.executeSql("select * from TMP_AUD WHERE CRE_BY=? AND AUD_NUMBER=? ",
[localStorage.getItem("user_name"), testSO.auditNumber]).then(
response => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB- folder'+response.rows.length+'ID= '+response.rows.item(0).FLD_NUMBER);
if (response && response.rows && response.rows.length > 0) {
if (response && response.rows && response.rows.length > 0) {
var FLD_NUMBER = response.rows.item(0).FLD_NUMBER;
var folderArray = []
observableBatch.push(db.executeSql("select * from TMP_FOLDER WHERE CRE_BY=? AND FLD_NUMBER=? ",
[localStorage.getItem("user_name"), FLD_NUMBER]).then(
a => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FOLDER'+a.rows.length);
if (a && a.rows && a.rows.length > 0) {
for (let i = 0; i < a.rows.length; i++) {
var folderObj = {
folderName: a.rows.item(i).FLD_NAME,
files:[]
}
var FLD_NAME = a.rows.item(i).FLD_NAME
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FOLDER '+FLD_NAME);
observableBatch.push( db.executeSql("select * from TMP_FILES WHERE CRE_BY=? AND FLD_NAME=? ",
[localStorage.getItem("user_name"), FLD_NAME]).then(
b => {
this._util.logData('In downloadPendingInstancesForSyncFromOfflineDB-TMP_FILES'+b.rows.length);
var fileArray = [];
if (b && b.rows && b.rows.length > 0) {
for (let j = 0; j < b.rows.length; j++) {
var fileSO = {
compliance: b.rows.item(j).COMPLIANCE,
remarks: b.rows.item(j).REMARKS,
fileName: b.rows.item(j).FILE_NAME,
title: b.rows.item(j).TITLE
}
);
fileArray.push(fileSO);
}}
folderObj.files=fileArray;
}).catch(
e => {
this._util.logData('For sync error'+JSON.stringify(e));
return Observable.throw("An error occurred during sync");
})
);
folderArray.push(folderObj);
}}
}).catch(
e => {
this._util.logData('For sync error'+JSON.stringify(e));
return Observable.throw("An error occurred during sync");
})
);
}
}
testSO.folderArray = folderArray;
this._util.logData('Candidate for selected for sync' + JSON.stringify(testSO));
})
);
return Observable.forkJoin(observableBatch);
}
The issue here is below method is not waiting for all the calls to finish
public getFiles(testSO) {
return Observable.create(observer => {
this.platform.ready().then(() => {
this.sqlite.create({
name: 'offline.db',
location: 'default'
}).then((db: SQLiteObject) => {
this.downloadFromOfflineDB(db, testSO).subscribe(c => {
observer.next(c[0]);//This is undefined
observer.complete();
},
error => {
observer.error("An error occurred sync files.");
});
});
});
});
}
First method is executing, while second method returns before first execution is complete and I am not getting my object testSO populated. Can someone please guide me and tel me what I am doing wrong here.I used observable fork Join.
Looks like you are calling Observable.forkJoin(observableBatch) with only one item - result of db.executeSql. When you add more items later on it doesn't affect forkJoin.

Maybe-type of generic type parameter is incompatible with empty

For every instantiation of RemoteEntity, I get an error on the type parameter that This type is incompatible with empty, referencing the null value for value in newRemoteEntity:
export type RemoteEntity<T: Identifiable> = {
value: ?T;
error: ?Error;
// ...
}
export function newRemoteEntity(): RemoteEntity<*> {
return {
value: null, // error
error: null, // OK
// ...
}
}
If I instead declare value: ?Object, these errors go away (but then I get other errors related to the loss of my type bound). Am I missing something or is this Flowtype bug/quirk?
I found a workaround by making the fields optional (instead of required but with a maybe-type). However, it makes other code a little more complicated (since I have to check for nulls instead of just propagating them in object literals), so I would prefer having maybe-types work.
export type RemoteEntity<T: Identifiable> = {
value?: T;
error?: Error;
pendingAction: ?string;
// ...
}
export function newRemoteEntity(): RemoteEntity<*> {
return {
pendingAction: null,
// ...
}
}
export function requested<T: Identifiable>(
state: RemoteEntity<T>, action: string, id?: string): RemoteEntity<T> {
// Maybe-type version was more concise:
// return {
// state: id && state.value && state.value.id === id ? state.value : null,
// error: null,
// pendingAction: action,
// // ...
// }
const result: RemoteEntity<T> = {
pendingAction: action,
// ...
}
if (id && state.value && state.value.id === id) {
result.value = state.value
}
return result
}

extending firebase.database.Reference

in the old FB I added a helper function to get/set values as follows:
// val() -> get(), resolve with value at ref
// val(value) -> set(value), resolve with value
// val(vals) -> update(vals), resolve with vals
Firebase.prototype.val = function(vals) {
let self=this;
if (!vals) {
return this.once('value').then(
snapshot => {
if (typeof snapshot.val() === 'undefined' || snapshot.val() === null) throw 'INVALID_VALUE';
return snapshot.val();
},
err => {
throw err;
});
}
let singleVal=(vals.constructor != Object); // is singleVal then vals is a single value
if (singleVal ) return this.set(vals); // set single value
if (!singleVal) return this.update(vals).then(() => vals); // update multiple values
};
}
I could then do for example return ref.child(...).val();
This function does not run in V3.
How can I extend firebase in that way in V3 ?
thx!
Here's the solution - I find this extension very handy
// val() -> get(), resolve with value at ref, fails with error.code
// val(value) -> set(value), resolve with value, fails with error.code
// val(vals) -> update(vals), resolve with vals, fails with error.code
firebase.database.Reference.prototype.val = function(vals) {
let path=this.toString().substring(firebase.database().ref().toString().length-1);
let valsAsString = (typeof vals==='string' ? vals : JSON.stringify(vals));
if (!vals) {
return this.once('value').then(
snapshot => {
if (typeof snapshot.val() === 'undefined' || snapshot.val() === null) {
console.log('val('+path+') failed (null) ! '+error.message+' ('+error.code+')');
throw 'INVALID_VALUE';
}
return snapshot.val(); },
error => {
console.log('val('+path+') failed ! '+error.message+' ('+error.code+')');
throw error.code;
});
}
let singleVal=(vals.constructor != Object); // is singleVal then vals is a single value
if (singleVal ) return this.set(vals).then( // set single value
() => {
return vals;
}, error => {
console.log('val('+path+','+valsAsString+') failed ! '+error.message+' ('+error.code+')');
throw error.code;
}
);
return this.update(vals).then( // update multiple values
() => {
return vals;
}, error => {
console.log('val('+path+','+valsAsString+') failed ! '+error.message+' ('+error.code+')');
throw error.code;
}
);
};
}

Resources