React Redux Firebase check if value exist before dispatch - reactjs

Not sure how to check if data exist using redux, anyone have a quick answer?
export function fetchName(name) {
return dispatch => {
const guestsRef = database.ref('/guest').set({
name
})
.then(function (snapshot) {
dispatch(setName({
name
}));
});
}
}
This code just overwrites same entry and clears all data.

const guestRef = database.ref('/guest');
guestRef.once('value', snapshot => {
const guest = snapshot.val();
if(!guest || !guest.name) {
guestRef.set({ name });
}
});
OR
try {
const guest = (await database.ref('/guest').once('value')).val();
if(guest == null) {
const updates = { name };
await database.ref('/guest').update(updates);
//await database.ref('/guest').set({ name });
}
} catch (error) {
//error handling
}

If you wish to abort a particular function you can return false at anytime.
export function fetchName(name) {
return dispatch => {
const guestsRef = database.ref('/guest').set({
name
})
.then(function (snapshot) {
if ( snashot ) { return false; }
dispatch(setName({
name
}));
});
}
}
This way you avoid invoking dispatch and overwritting your data.

Related

How to make a PATCH request in ReactJS ? (with Nestjs)

nestjs controller.ts
#Patch(':id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
#Body('shippingAddr') addrShipping: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling, addrShipping);
return null;
}
nestjs service.ts
async updateProduct(
addressId: string,
addrBilling: boolean,
addrShipping: boolean,
) {
const updatedProduct = await this.findAddress(addressId);
if (addrBilling) {
updatedProduct.billingAddr = addrBilling;
}
if (addrShipping) {
updatedProduct.shippingAddr = addrShipping;
}
updatedProduct.save();
}
there is no problem here. I can patch in localhost:8000/address/addressid in postman and change billingAddr to true or false.the backend is working properly.
how can i call react with axios?
page.js
const ChangeBillingAddress = async (param,param2) => {
try {
await authService.setBilling(param,param2).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
return....
<Button size='sm' variant={data.billingAddr === true ? ("outline-secondary") : ("info")} onClick={() => ChangeBillingAddress (data._id,data.billingAddr)}>
auth.service.js
const setBilling = async (param,param2) => {
let adressid = `${param}`;
const url = `http://localhost:8001/address/`+ adressid ;
return axios.patch(url,param, param2).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}
I have to make sure the parameters are the billlingddress field and change it to true.
I can't make any changes when react button click
Since patch method is working fine in postman, and server is also working fine, here's a tip for frontend debugging
Hard code url id and replace param with hard coded values too:
const setBilling = async (param,param2) => {
// let adressid = `${param}`;
const url = `http://localhost:8001/address/123`; // hard code a addressid
return axios.patch(url,param, param2).then((response) => { // hard code params too
console.log(response); // see console result
if (response.data.token) {
// localStorage.setItem("user", JSON.stringify(response.data));
}
// return response.data;
})
}
now it worked correctly
#Patch('/:id')
async updateProduct(
#Param('id') addrId: string,
#Body('billingAddr') addrBilling: boolean,
) {
await this.addrService.updateProduct(addrId, addrBilling);
return null;
}
const ChangeBillingAddress = async (param) => {
try {
await authService.setBilling(param,true).then(
() => {
window.location.reload();
},
(error) => {
console.log(error);
}
);
}
catch (err) {
console.log(err);
}
}
const setBilling= async (param,param2) => {
let id = `${param}`;
const url = `http://localhost:8001/address/`+ id;
return axios.patch(url,{billingAddr: param2}).then((response) => {
if (response.data.token) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
}

How to return boolean value from custom function in react

I have an app that takes in an object named user. The user object has userId information which is needed to get information from firestore database if the person is a paid member or not, membership is either true or false. If the person is a non-paid member than i want to display a button, and if he is a paid member, than i want the button to not be displayed. The problem i am having is how to return a boolean from the PaidMembership() function?
const App = ({ user, database }) => {
const PaidMembership = () => {
var test = null;
docRef.get().then(function(doc) {
if (doc.exists) {
test = doc.data().membership;
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
test = false;
}
})
return test;
}
return (
{ PaidMembership() ? render : dont render}
)
}
Make test variable inside state and check
const [test, setTest] = useState(null);
const App = ({ user, database }) => {
const PaidMembership = () => {
docRef.get().then(function(doc) {
if (doc.exists) {
setTest( doc.data().membership);
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
setTest(null);
}
})
return test;
}
return (
{ test ? "" : <button>show button</button>}
)
}
This is because docRef.get returns promise and you are treating it as a normal function call. Try using this :
const App = async ({ user, database }) => {
const PaidMembership = async () => {
const doc = await docRef.get();
return doc.exists;
};
return (await PaidMembership()) ? "render" : "dont render";
};

Dispatch multiples http request React/Redux

I'm trying to dispatch more than one axios request inside my method. However, it is not working.
export const getImages = (res) => {
return {
type: actionTypes.GET_IMAGES,
payload: res
}
}
export const loadImages = (imgs, cId) => {
return dispatch => {
let data = [];
for(const i of imgs) {
const id = i.id;
axios.get(`${api.URL}/test/${cId}/files/${id}`)
.then(res => {
if(res.data !== -1) {
const obj = {
name: res.data,
desc: i.caption
};
data(obj);
}
//dispatch(getImages(data));
});
}
console.log('Action:');
console.log(data);
dispatch(getImages(data));
}
}
The console log does not print anything. Do I need to dispatch inside the .then()? If so, how can I run multiples requests before dispatching?
Thanks

No function is getting called inside firebase get function

I am trying to write login code, but this firebase get function is refraining me to do so. I am unable to call any function (except alert), within this get function. Navigating to another component also does not work here. I know I have to use async/await keywords but I dont know how to. Can someone please help me with this?
Pasting the code below.
navigate() {
alert("Aya");
}
login() {
const { uname } = this.state;
const { password } = this.state;
var userid = "";
var data;
if (uname && password) {
firebase
.auth()
.signInWithEmailAndPassword(uname, password)
.then(async user => {
userid = await firebase.auth().currentUser.uid;
await db.collection("Users").doc(userid)
.get()
.then(function (doc) {
if (doc.exists) {
data = doc.data();
alert(JSON.stringify(data.role));
if (data.role === "Company Admin") {
logged = true;
alert("Yahoo");
this.navigate();
}
else {
logged = false;
}
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function (error) {
console.log("Error getting document:", error);
});
})
.catch(error => {
alert(error);
this.setState({ error });
});
if (logged) {
alert(logged);
}
else {
alert("Nope");
}
}
else {
alert("Enter all fields data");
}
}
Don't use normal function, you are going to lose the context of this. The this in the callback function is not pointing to your class. So this.navigate() line of code won't work
.then(function (doc) {
As a solution, Use arrow function.
...
.then((doc) => {
...

Trying to modify a data from a React Promise Response changes globally

I have created a codesandbox with a simplified version of my problem
https://codesandbox.io/s/new-react-context-api-ei92k
I get something from a fetch (in this case a user)
I then create a local copy of this user and make some changes to it
The problem: Any changes update my initial user object
Can someone tell me how this is possible? and how can I avoid this?
import React, { useState, useEffect } from "react";
import { AppSessionContext } from "./AppContext";
import Header from "./Header";
const user = {
userName: "jsmith",
firstName: "John",
lastName: "Smith",
isAdmin: true
};
const loadProfile = () => Promise.resolve(user);
function createUserWithNewName(userToUpdate) {
userToUpdate["userName"] = "Dummy";
return userToUpdate;
}
const App = () => {
const [user, setUser] = useState({});
const [Loaded, setLoaded] = useState(false);
var amendedUser = {};
useEffect(() => {
loadProfile()
.then(user => {
setUser(user);
console.log(user);
})
.then(() => {
amendedUser = createUserWithNewName(user);
console.log(amendedUser);
console.log(user);
})
.then(setLoaded(true));
}, []);
if (!Loaded) {
return "Loading";
}
return (
<AppSessionContext.Provider value={{ user }}>
<div className="App">
<Header />
</div>
</AppSessionContext.Provider>
);
};
export default App;
snippet of production code
loadTableDefault() {
fetch(defaultUrl(), {method: 'GET'})
.then(res => res.json())
.then(response => {
this.setState({
data: response,
})
return response
})
.then(response => {
this.setState({
table_data: formatResponsePretty(response),
})
})
.catch(error => console.error('Error:', error));
}
formatResponsePretty
export function formatResponsePretty(oldData) {
const newData = {
...oldData,
};
// consider re-writting the flask response to this format
const obj = { allocations: [] };
var theRemovedElement = ''
var ports = []
ports = Object.values(newData['allocations']['columns']);
ports.shift();
var dataArray = ['allocations', 'conditions', 'liquidity', 'hedging']
for (const index of dataArray) {
for (const i of newData[index]['data']) {
theRemovedElement = i.shift();
if (index === 'allocations') {
obj[index][theRemovedElement] = i
}
else {
obj[theRemovedElement] = i;
}
}
}
const rows = []
let index = 0;
Object.keys(obj).forEach(element => {
index = formatting.findIndex(x => x.name === element)
if (formatting[index] && formatting[index]['type'] === 'number') {
var new_obj = obj[element].map(function (el) {
return Number(el * formatting[index]['multiplier']).toFixed(formatting[index]['decimal']) + formatting[index]['symbol']
})
rows.push(new_obj)
}
else if (formatting[index] && formatting[index]['type'] === 'string') {
rows.push(obj[element])
}
else if (formatting[index] && formatting[index]['type'] === 'boolean') {
// there should be logic here to display true or false instead of 1 and 0
// this could be in the upload
rows.push(obj[element])
}
else {
rows.push(obj[element])
}
})
const arrOfObj = createRecords(ports, rows)
return {obj: obj, ports: ports, rows: rows, arrOfObj: arrOfObj}
}
In createUserWithNewName() you are updating the original user object and returning it.
You instead want to create a new object with all the old user properties, but with just the username changed. Thankfully, object destructuring makes this super easy:
function createUserWithNewName(oldUser) {
const newUser = {
...oldUser,
userName: 'Dummy',
};
return newUser;
}
This will copy all the properties of oldUser to a new object and then just update userName!
You're also going to want to pass user down to that second .then() as it won't currently be available in there:
.then(user => {
setUser(user);
console.log(user);
return user;
})
.then(user => {
amendedUser = createUserWithNewName(user);
console.log(user, amendedUser);
})
Update CodeSandbox link: https://codesandbox.io/s/new-react-context-api-tgqi3

Resources