How to update value in client site using mongodb? - node.js

I am using React in front-end and Node and MongoDB in Back-end. I have created a custom hook from where I am loading the data. The following is the custom hook
import { useEffect, useState } from "react";
const useItems = (id) => {
const [item, setItem] = useState([]);
useEffect(() => {
fetch(`http://localhost:5000/inventory/${id}`)
.then((res) => res.json())
.then((data) => setItem(data));
}, [id]);
return [item];
};
export default useItems;
And this is the component where I am calling the custom hook to load the data.
import React, { useEffect, useState } from "react";
import "./Inventory.css";
import { useParams } from "react-router-dom";
import useItems from "../../hooks/useItems";
const Inventory = () => {
const { id } = useParams();
const [item] = useItems(id);
const quantityDecrease = (newQuantity) => {
let quantity = parseInt(newQuantity) - 1;
const updateQuantity = { quantity };
const url = `http://localhost:5000/inventory/${id}`;
fetch(url, {
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(updateQuantity),
})
.then((res) => res.json())
.then((data) => {
console.log("success", data);
alert("saved");
});
};
return (
<div>
<div className="col-lg-6">
<p className="inventory-textbox">
<strong>Quantity :</strong> {item.quantity}
</p>
</div>
<button onClick={() => quantityDecrease(item.quantity)}>
Delivered
</button>
</div>
);
};
export default Inventory;
Whenever the Delivered button is clicked the quantityDecrease function is executed and the quantity of the item is decreased by one. Now, my database is working fine. I am being able to update both client and server site but I have to reload the page in order to see the change in the ui. Is there a way I do not have to reload to see the change?

try using the item data as useEffect dependency. it may solve your problem.

Related

NodeJS Axios - Cant show my get request on screen

On this case I am trying to show the "_id".
I made the code based on this video.
But by just looking at his API I can see that his data is little different, how can I adapt it to work with my API
import "./App.css";
import axios from "axios";
import { useEffect, useState } from "react";
const App = () => {
const [leitura, setLeitura] = useState([]);
const getLeituraData = async () => {
try {
const data = await axios.get(
"https://estufaarduino.herokuapp.com/sistema/leituras"
);
console.log(data.data);
setLeitura(data.data);
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getLeituraData();
}, []);
return (
<div className="App">
{leitura.map((item) => {
return <p>{item._id}</p>;
})}
</div>
);
};
export default App;

window.stripe is not a function

I am trying to create a stripe checkout project but was stuck when I found that the loadStripe promise was not working fine and I have to change the code window.stripe but this is also not working .
Her is my react code :
import React, { useEffect, useRef } from "react";
import { isAuth } from "../helpers/auth";
import { useNavigate } from "react-router-dom";
import styles from "./Pricing.module.scss";
import ScriptTag from "react-script-tag";
const Stripe = require('stripe')
const stripe = window.Stripe('pk_8734579834958')
export const Pricing = () => {
const buttonValue = useRef();
const navigate = useNavigate();
const setBtnValue = (e) => {
buttonValue.current = e.target.value;
};
const checkoutHandler = async (e) => {
const btnValue = buttonValue.current;
console.log(btnValue);
fetch("http://localhost:5000/api/checkout", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
btnValue,
}),
})
.then((result) => result.json())
.then(({ sessionID }) => stripe.redirectToCheckout({ sessionID }))
.then((result) => {
console.log(result.error.message);
});
};
return (
<div>
<ScriptTag
isHydrating={true}
type="text/javascript"
src="https://js.stripe.com/v3/"
/>
<form onSubmit = {checkoutHandler}>
<button
value= 'price_bdsahfbadshb'
type="submit"
className="btn"
name="product"
onClick={setBtnValue}
>
Upgrade Now
</button>
</div>
)
}
Here is my backend code :
router.post('/checkout' , async(req,res) => {
const product = req.body;
console.log(product);
}
As you want to redirect, just try adding <script src="https://js.stripe.com/v3/"></script> into index.html (if not added) so you will able to use window.Stripe.
and remove line const Stripe = require('stripe')
if you want more clarification, go through its official documentation.

useState not updating state object after fetching data from API endpoint

Just starting to learn React. I wrote a simple web server that serves data from a /users endpoint. I am fetching that data in useState hook of a component, but the state object does not seem to be updating. Anyone that can point me in the right direction to get the response object data to render in the ordered list would be greatly appreciated.
import { useState, useEffect } from 'react';
const UserList = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("http://localhost:8080/users",
{
method: "GET"
}
)
.then(res => res.json())
.then(res => {
setUsers(res.data);
})
.catch(err => {
console.log(err);
});
}, []);
return (
<div>
<h1>User List</h1>
<ol>
{
users.forEach(u => {
<li>{u}</li>
})
}
</ol>
</div>
)
}
export default UserList;
Issue
You are using Array.prototype.forEach to try and render your state. .forEach is a void return, however, so nothing is returned to be rendered.
Solution
Use Array.prototype.map to map the users state to JSX.
{
users.map((u, index) => (
<li key={index}>{u}</li>
))
}

React protected route using axios & JWT

I am trying to make a protected route with Reatjs, nodejs and JWT. The problem is that my component renders before my API checked the client token. This is the code I am trying :
import React, {useState, useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom';
import AuthAPI from './../utils/AuthAPI';
const ProtectedRoute = ({children, ...rest}) => {
const [isAuth, setIsAuth] = useState(false);
const fetchData = async () => {
await AuthAPI.isAuth((res)=>{ //API call
setIsAuth(res);
});
}
useEffect(()=>{
fetchData();
},[]);
return (
<Route {...rest}
render={(props)=>{
return(
isAuth ? children : <Redirect to='/' />
);
}}
/>
);
};
And this is the API call :
static isAuth(callback){ //static method from the class 'AuthAPI' imported above
const url = 'http://localhost:5000/api/Auth/checking';
const options = {
method: 'GET',
url: url,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;charset=UTF-8',
},
data: {}
}
return axios(options)
.then((response)=>{
callback(true);
}).catch((err)=>{
callback(false);
});
}
When I load the page, it directly redirects since the state isAuth is set to false by default.
I already used this model of code to display a list of things gotten from an API and it worked fine. I assume it is not the best way to do that but most of the examples I have found are not using an actual API but just fake auth without using promises.
EDIT 1.2 :
I've tried this code, from Udendu Abasili :
import React, {useState, useEffect} from 'react';
import { Route, Redirect } from 'react-router-dom';
import AuthAPI from './../utils/AuthAPI';
const ProtectedRoute = ({children, ...rest}) => {
const [isAuth, setIsAuth] = useState(false);
const [isLoaded, setIsLoaded] = useState(false)
useEffect(()=>{
let mounted = true;
AuthAPI.isAuth().then(()=>{
if (mounted) {
console.log("Worked"); //display Worked
setIsLoaded(true); // This line 1
setIsAuth(true); // This line 2
}
}).catch(()=>{
if (mounted) {
console.log("Failed");
setIsLoaded(true);
setIsAuth(false);
}
});
return () => {
mounted = false;
}
},[]);
return (
!isLoaded ?
<h5>Loading</h5> : (
<Route {...rest}
render={(props)=>{
console.log("--->",isAuth,",",isLoaded); // displays false, true
return(
isAuth ? children : <Redirect to='/' />
);
}}
/>
)
);
};
export default ProtectedRoute;
I have found a weird bug. If I swap the lines commented as 'line 1' and 'line 2', it works otherwise it doesn't.
The way react js lifecycle works, the return component gets called before useEffect(which the hook equivalent of componentDidMount on the first mount). So you need to create a form of loader component ( replace the <Text>Loading</Text> with an actual CSS loader ) that waits for your isAuth function to finish.
const ProtectedRoute = ({children, ...rest}) => {
const [isAuth, setIsAuth] = useState(false);
const [loaded, setLoaded] = useState(false);
const fetchData = async () => {
//you need to add try catch here
await AuthAPI.isAuth((res)=>{ //API call
setIsAuth(res);
setLoaded(true)
});
}
useEffect(()=>{
fetchData();
},[]);
return (
loaded ?
<Text>Loading</Text> : (
<Route {...rest}
render={(props)=>{
return(
isAuth ? children : <Redirect to='/' />
);
}}
)
/>
);
};
As you rightfully said, this is not the best way to do it. I won't recommend calling a function to check authentication in the protected route component. Typically, I just pass an isAuthenticated paramter to ProctectedRoute component which gets updated with help of Redux. You should look it up

I'm fetching dynamic data from my nodejs to reactjs but I get an error saying "POST IS NOT DEFINED"

I have made entries in my mongodb database using node now I'm trying to fetch that data from backend to react front-end the 3rd party app used for cross-platform in node are cors and for react is axios(in script I have added "proxy":"http://localhost:5000"(5000 is my backend port)
Here is my code for NovelCard.js
import React, { Component } from 'react';
import { Container } from 'react-bootstrap';
import Card from 'react-bootstrap/Card';
import axios from 'axios';
const createSet = (post) => {
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="holder.js/100px180" />
<Card.Body>
<Card.Title>{post.name}</Card.Title>
<Card.Subtitle className="mb-2 text-muted">{post.author}</Card.Subtitle>
<Card.Text>{post.synopsis}</Card.Text>
</Card.Body>
</Card>;
};
class Latest extends Component {
state = {
name: '',
author: '',
synopsis: '',
post: [],
};
componentDidMount = () => {
this.getData();
};
getData = () => {
axios
.get('http://localhost:5000/novels/')
.then((res) => {
const data = res.data;
this.setState({ post: data });
console.log('data recived');
})
.catch(() => {
alert('error');
});
};
render() {
console.log('state', this.state);
return <Container>{post.map(createSet)}</Container>;
}
}
export default Latest;
I'm getting error saying ***
src\components\home\Latest\NovelCard.js Line 45:24: 'post' is not
defined no-undef
Your post variable is available within you state. You need to do something like this within your render function.
render() {
console.log('state', this.state);
return <Container>{this.state.post.map(createSet)}</Container>;
}
Or you can do like this as well.
render() {
const { post } = this.state;
console.log('state', this.state);
return <Container>{post.map(createSet)}</Container>;
}

Resources