Review and rating implementation of the doctor - reactjs

Issue: State variable inside a api call is not getting updated
Description: Hi I am trying to implement the doctor review part of the application. where anyone can write the review of the doctor. when i am writing the review on submission of review am calling review creation api using axios.post inside then i am trying to update the review count state variable but it is not getting updated it is showing old value not the latest one
initial review count =1
submit a new review
review count should be 2
but when logging it is showing 1
how can i call a single api call to update review count inside the submit review. currently i am calling put api 2 times to update review count and recommendation review count
also i want to update doctor object with reviewcount and reco review count and pass this other page
doctor={...doctor,review_count:reviewcount,recommendation_count:recoreviewcount}
navigation.navigate("DoctorDetail",doctor);
as state variable is not getting updated it is holding the old value
review_count:reviewcount,recommendation_count:recoreviewcount
Example code....
----------
const ShareYourStory = ({ navigation, route }) => {
const doctor = route.params;
const [recovalue, setRecoValue] = useState();
const [waittimevalue, setWaitTimeValue] = useState(0);
const [isfriendliness, setFriendliness] = useState(false);
const [isexplainhealthissue, setExpIssue] = useState(false);
const [issatisfaction, setSatisfaction] = useState(false);
const [issue, setIssue] = useState("");
const [reviewcomment, setReviewComment] = useState("");
const [reviewcount, setReviewCount] = useState(0);
const [recoreviewcount, setRecoReviewCount] = useState(0);
//comment
const submitFeedback = () => {
console.log("submit patient feedback");
console.log('reviewcountstatus',reviewcountstatus,'recoreviewcountstatus',recoreviewcountstatus);
var most_happy_about = "";
if (isfriendliness)
most_happy_about = most_happy_about + "Doctor Friendliness,";
if (isexplainhealthissue)
most_happy_about = most_happy_about + "Explaination of Health Issue,";
if (issatisfaction)
most_happy_about = most_happy_about + "Treatment satisfaction";
var reviewer_name = "Vikram";
let reviewinfo = {
doctor: `${doctor._id}`,
reviewer_name: `${reviewer_name}`,
is_doctor_recommended: `${recovalue}`,
review: `${reviewcomment}`,
issue_for_visit: `${issue}`,
most_happy_about: `${most_happy_about}`,
};
//console.log(reviewinfo);
axios
.post(`${host}/api/v1/reviews`, reviewinfo)
.then((res) => {
if (res.status == 201) {
// fetch no of review count from review table based on doctor id
var reviewurl = `${host}/api/v1/reviews?doctor=${doctor._id}`;
console.log("reviewurl", reviewurl);
axios
.get(reviewurl)
.then((res) => {
console.log("reviewcount", res.data.count);
if (res.data.count > 0) {
setReviewCount(res.data.count);
const updatereviewcount = {
review_count: `${reviewcount}`
};
axios
.put(`${host}/api/v1/doctors/${doctor._id}`, updatereviewcount)
.then((res) => {
if(res.status == 200 || res.status == 201) {
console.log('status',res.data);
}
})
.catch((error) => {
console.log('error',error);
})
}
})
.catch((err) => {
console.log(err);
});
// calculate doctor_recommended_percent value
var recoreviewurl = `${host}/api/v1/reviews?doctor=${doctor._id}&is_doctor_recommended=Yes`;
console.log("recoreviewurl", recoreviewurl);
axios
.get(recoreviewurl)
.then((res) => {
console.log("recoreviewcount", res.data.count);
if (res.data.count > 0) {
setRecoReviewCount(res.data.count);
const updaterecoreviewcount = {
doctor_recommended_percent: `${recoreviewcount}`
};
axios
.put(`${host}/api/v1/doctors/${doctor._id}`, updaterecoreviewcount)
.then((res) => {
if(res.status == 200 || res.status == 201) {
console.log('status',res.data);
}
})
.catch((error) => {
console.log('error',error);
})
}
})
.catch((err) => {
console.log(err);
});
console.log(recoreviewcountstatus,reviewcountstatus);
}
})
.catch((err) => {
console.log("feedback review creation failed", err);
});
};
}

Related

State Not Finished Setting before being used in useEffect

I am hosting a react app in aws amplify using the aws-serverless version of express as the REST API, which sits inside of a lambda function. A big problem that I am facing is that asynchronous jobs in aws-serverless express cause the lambda function to complete before the promises resolve. Leaving me with no data and no error handling. This caused me to bring a lot of the asynchronous work to the front end of the application.
The problem here is that I need to bring a large amount of data into state. Right now, I am using a delay workaround (shown below) but instead need a programatic way to make sure state is finished updating before being used in the second useEffect hook (dependent on odds & failedTries props) instead of using the delay functionality.
Any help would be greatly appreciated.
const App = ({ signOut }) => {
const [odds, setOdds] = useState([]);
const [updateTime,setUpdateTime] = useState(0);
const [failedTries,setFailedTries] = useState(0);
useEffect(() => {
const setNflOdds = async () => {
let response = await updateNflOdds();
let data = response;
setOdds(data);
};
setNflOdds();
setUpdateTime(1);
const interval = setInterval(() => {
setNflOdds();
setUpdateTime(updateTime => updateTime +1);
}, 100000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const s3Push = (() => {
if(!odds.length) {
setFailedTries(failedTries => failedTries + 1);
} else {
const delay = ms => new Promise(res => setTimeout(res, ms));
const nflOddsRefDelay = async() => {
*//This is the current workaround, wait ten seconds before pushing odds state up to the s3 bucket*
await delay(10000);
oddsS3Helper(odds);
};
nflOddsRefDelay()
}
});
s3Push();
}, [odds, failedTries]);
With the above indicated delay workaround this works for my use case (13k records inside of the array) but the data size is highly variable and I want to figure out a way that no matter the data size it brings the entire call up to the s3 bucket.
below is the content of the functions being called in the useEffect hook
const pushToS3 = async ( file, key ) => {
const creds = await Auth.currentCredentials()
const REGION = {region};
const s3Client = new S3Client({
credentials: Auth.essentialCredentials(creds),
region: REGION
});
const params = {
Bucket: {s3 bucket name}
Key: key,
Body: file,
};
s3Client.send(new PutObjectCommand(params));
console.log("file is sent");
};
const oddsS3Helper = (async (odds) => {
console.log("inside s3 helper: ",odds);
let csv = '';
let headers = Object.keys(odds[0]).join(',');
let values = odds.map(odd => Object.values(odd).join(',')).join('\n');
csv += headers + '\n' + values;
const buffedFile = csv;
const key = 'nflprops.csv'
const delay = ms => new Promise(res => setTimeout(res, ms));
const propRefDelay = async() => {
await delay(5000);
await postNflOdds();
};
pushToS3( buffedFile, key );
await propRefDelay();
});
async function getNflGames() {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {} // OPTIONAL
};
const data = await API.get(apiName, path, init);
return data;
};
async function getNflOdds(gameId) {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {}, // OPTIONAL
body: { gameId }
};
const data = await API.post(apiName, path, init);
return data;
};
async function updateNflOdds() {
const ojNflGames = await getNflGames();
const nflGameProps = [];
const nflOddsPush = ( async () => {
try {
await ojNflGames.data.map( async (game) => {
const ojNflOdds = await getNflOdds(game.id)
await ojNflOdds.data[0].odds.map((line) => {
nflGameProps.push(
{
gameId: game.id,
oddsId: line.id,
sports_book_name: line.sports_book_name,
name: line.name,
price: line.price,
checked_date: line.checked_date,
bet_points: line.bet_points,
is_main: line.is_main,
is_live: line.is_live,
market_name: line.market_name,
home_rotation_number: line.home_rotation_number,
away_rotation_number: line.away_rotation_number,
deep_link_url: line.deep_link_url,
player_id: line.player_id,
}
);
});
});
} catch (err) {
console.log("there was an error", err);
}
});
try {
await nflOddsPush();
} catch(err) {
console.log("odds push errored: ", err);
}
console.log("inside of updateNflOdds function: ",nflGameProps);
return nflGameProps;
};

Reactjs UseState & UseEffect Messing

Below is a code i am using to set state for some data:
const [loader, setLoader] = useState(true);
const [trendData, setTrend] = useState([]);
const [thisMonthData, setThisMonth] = useState([]);
useEffect(() => {
graphData();
}, [loader]);
async function graphData() {
await getRequest(process.env.REACT_APP_apiUrl + ':0000/abc/xyz').then( (response) => {
let series = [];
let months;
for (let index = 0; index < response.length; index++) {
months = response[index]['Month'].split(',');
series.push(response[index]['Useres'].split(','));
}
setTrendMonth(series);
setThisMonthData(series);
console.log(thisMonthData);
setLoader(false);
});
}
And now i am attaching a response getting in console.log(thisMonthData); this. I have tried everything, including thisMonthData in useEffect and other state keys. But everytime data is going blank or missing values.
Whats wrong here.
enter image description here
enter image description here
You are mixing await and then, also try to log thisMonthData when they are changed with a useEffect:
useEffect(() => {
graphData();
}, [loader]);
useEffect(() => {
console.log(thisMonthData);
}, [thisMonthData]);
async function graphData() {
try {
const response = await getRequest(
process.env.REACT_APP_apiUrl + ':0000/abc/xyz'
);
let series = [];
let months;
for (let index = 0; index < response.length; index++) {
months = response[index]['Month'].split(',');
series.push(response[index]['Useres'].split(','));
}
setTrendMonth(series);
setThisMonthData(series);
setLoader(false);
} catch (err) {
console.log(err);
}
}
Hi Sandeep Singh,
Does the function getRequest() use axios or already does the .json() in some step? Like in the ex:
fetch(myRequest)
.then((response) => response.json())
.then((data) => {/***/}

useEffect didnt run

So i have this function that i want to run once when the app start. This function task is to create userId then i will run another function to fetch data from firebase with the userId that created before. But the fetch function didn't start or it didnt do the task well, there is no sign of error, that's what make it more confusing. If i press the fetch function by button it work correctly.
the state
const [task, setTask] = useState(); // bisa di sebut sebagai controller text input
const [taskItems, setTaskItems] = useState([]); // state untuk list task
const [userId, setUserId] = useState();
const [isLoading, setIsLoading] = useState(true);
const baseUrl =
'https://react-http-post-RANDOM_KEY-default-rtdb.firebaseio.com/task/' + userId;
this is function to create userId function on init app
const handleCreateUser = async () => {
setIsLoading(true);
try {
const value = await AsyncStorage.getItem('userId');
if (value !== null) {
setUserId(value);
} else {
const uniqueId = makeid(6);
await AsyncStorage.setItem('userId', 'user' + uniqueId);
setUserId('user' + uniqueId);
}
await fetchDatabase();
} catch (error) {
console.log('errorrr AsyncStorage' + error);
}
setIsLoading(false);
};
this is function to fetch data from firebase
const fetchDatabase = async () => {
console.log('infinite looping');
try {
const response = await fetch(baseUrl + '.json');
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
} catch (error) {
setError(error.message);
}
};
this is how i call the useEffect
useEffect(() => {
handleCreateUser();
}, []);
The first thing I see is that you are not using await correctly. It should be before fetchDatabase(); function that is inside handleCreateUser like so:
await fetchDatabase();
The word await is there when you have to call an asynchronous function and you have to wait for this function to be completed.
Edit
To use only one useEffect you can check if your fetch function received your data by:
// or whatever statusCode you get when the data are present
if(reponse.statusCode === 200) {
// the await is not needed because it is present for the reponse abov
const data = response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
}
i got the answer, by using 2 useEffect
useEffect(() => {
handleCreateUser();
}, []);
useEffect(() => {
fetchDatabase();
}, [userId]);

Wrong value of state displayed after refreshing a page from useEffect()

I have a problem with my page that fetch data from a server and displays it for the user. I am using the hook useEffect for it.
My problem is that the first time I visit a page the correct data are displayed (so from /home I go to /product1 I get correct information). But after manually refreshing my page /product1 even though the server is getting the correct information again, my state object of my page will not update again. Is there a way to fix this? Code below:
const [productInfo, setProductInfo] = useState({
saleStarted : null,
quantityPerSize : []
})
useEffect(() => {
const fetchdata = async () => {
setLoading(true);
const query = new db.Query('Products');
query.equalTo('productId', params.productId);
await query.find()
.then(async (response) => {
setdata(response[0].attributes);
})
.catch((err) => {
setError(err);
console.log(err);
})
.finally(() => {
setLoading(false);
});
}
if(isInitialized){
fetchdata();
}
}, [isInitialized]);
useEffect(() => {
const saleStartedInfo = async() => {
const options = {
link : url + params.contractId,
}
try{
let started = await db.find(options)
console.log(started); //returns true
setProductInfo({...productInfo, saleStarted : started});
}catch(e){
console.log(e);
}
}
const quantitySize = async() => {
let _quantityBySize = [];
for(let k = 0 ;k<data.numberOfSize;k++) {
let options = {
address : url + params.contractId,
}
try{
let quantitySize = await db.find(options);
_quantityBySize.push(quantitySize)
} catch(err) {
console.log(err);
}
}
console.log(_quantityBySize); // let's say returns [5,4,10] if product has 3 size
setContractInfo({...contractInfo, quantityPerSize : _quantityBySize})
}
if(isInitialized && data){
saleStartedInfo();
quantityMinted();
}
}, [data])
So after rendering this page the first time it will show sale started, and quantity 5, 4 and 10. After refresh it will show sale not started and quantity === [] (empty array)

how to refactor duplicate API calls into a single API call?

I am pretty new to building full-stack applications, and I could like to avoid duplicating code in order to build the following to perform the calls in react my endpoints can be called like the following /api/v1/feeds/list/?page=${page} or api/v1/feeds/list/?search=${query} , but I would like to joing ?page=${page}&?search=${query} since search param is optional . I just want to make a single api call
async function fetchFeed(page) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?page=${page}`);
}
async function searchQuery(query) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?search=${query}`);
}
const Main = () => {
const [currentPage, setCurrentPage] = useState(1);
const [feed, setFeed] = useState([]);
const [feedCount, setfeedCount] = useState(0);
const [visible, setVisible] = useState(3)
const showMoreItems = () => {
setVisible(prevValue => prevValue + 3);
}
const browse = (page) => {
fetchFeed(page)
.then(function(response){
setfeedCount(response.data.count)
setFeed(response.data.results)
})
.catch(function(error){
console.log(error);
});
}
// fetches data
const fetchData = (search) => {
searchQuery(search)
.then((response) => {
setFeed(response.data.results)
})
.catch((error) => {
console.log(error);
});
};
const handleSearch = (e) =>{
fetchData(e.target.value);
}
useEffect(() => {
browse(currentPage)
fetchData(feed);
}, [currentPage]);
}
I'd pass an object with both page and query, which both default to the empty string - and if empty, don't include them in the fetched URL:
async function fetchFeed({ page = '', query = '' }) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?${page ? `page=${page}&` : ''}${query ? `search=${query}` : ''}`);
}
If possible, make your API accept empty query parameters too, allowing you to simplify to
return api.get(`http://localhost:8001/api/v1/feeds/list/?page=${page}&query=${query}`);
Something like this should work for you
const fetchFeed = async (page, query) => {
let url =`http://localhost:8001/api/v1/feeds/list/?page=${page}`
if(query) url += `?search=${query}`
return api.get(url)
}
const browse = (page search) => {
await fetchFeed(page search)
.then(function(response){
!search && setfeedCount(response.data.count)
setFeed(response.data.results)
})
.catch(function(error){
console.log(error);
});
}
useEffect(() => {
browse(currentPage) // just pass page
browse(currentPage, searchQuery); // pass both page and search query
}, [currentPage]);

Resources