Why my useState from Context doesn't update - reactjs

Hello I try to save the fatched data from my database to my variable selectedRestaurant. I use setSelectedrestaurant in the useEffekt hook but it doesn't update my variable. I get as a value null.
Here is my code
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
//const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const[ selectedRestaurant, setSelectedRestaurant]= useState(null);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
console.log(selectedRestaurant);
}
fetchData(id);
},[]);//Wichtig, damit es nur 1x
/*
useEffect(()=>{
console.log("useEffect2");
console.log(selectedRestaurant);
},[selectedRestaurant]);
*/
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
I know that useEffect is async so I tried with await setSelectedRestaurant(result.data.data)
but it didn't work. I also defined two useEffects that should invoke only once. One for changing and the other for update but both useEffects are invoked twice. I dont know why and how to solve it.
Hope u can help me

Try tidying up your sample code. There are lot of poorly formatter comments and spelling errors that make it difficult to parse.
EDIT:
When you update the state (i.e. setSelectedRestraunt) those changes are batched together don't change the state variable until the next render loop.
If you want to console.log or otherwise use the data, create a useEffect which is dependent on that value.
import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'react-router';
import RestaurantFinder from '../api/RestaurantFinder';
import { RestaurantsContext } from "../context/RestaurantsContext";
import Reviews from '../components/Reviews';
import StarComponent from '../components/StarComponent';
import AddReview from '../components/AddReview';
import Test from '../components/Test';
const RestaurantDetailedPage = (props) =>{
const{ selectedRestaurant, setSelectedRestaurant}= createContext(RestaurantsContext);
const {id} = useParams();
useEffect(()=>{
const fetchData = async(id)=>{
const result = await RestaurantFinder.get("/"+id);
console.log(result);
setSelectedRestaurant(result.data.data);
}
fetchData(id);
},[]);
useEffect(()=>{
console.log("Selected Restaurant:", selectedRestaurant);
},[selectedRestaurant]);
return(
<div>{selectedRestaurant && (
<>
<div>{<AddReview/>}</div>
<div></div>
</>
)}
</div>
)
}
export default RestaurantDetailedPage;
Original comment
With that in mind, your <Reviews> element is commented out, is that intentional?
{/* <Reviews reviewsObject={selectedRestaurant.reviews}/>*/}

Related

React JS coponent not rendering using map function

I hava a component called videoRow i try to render this component using dummy values now i get data from a useEffect Hook i have to use that data to render my component but when i try to do so it dont show anything. I even try console log to check weather i get my data or not it print my data on console means my useEffect is working But when i try this data on my videoRow component it not show anything
import React, { useState, useEffect } from "react";
import "../css/searchPage.css";
import TuneSharpIcon from "#mui/icons-material/TuneSharp";
import ChannelRow from "./ChannelRow";
import VideoRow from "./VideoRow";
import { selectInput } from "../features/inputSlice";
import { useSelector } from "react-redux";
import Axios from "axios";
function SearchPage() {
const getQuery = useSelector(selectInput);
const API_URL = `https://www.googleapis.com/youtube/v3/search?part=snippet&maxResults=4&key=APIKEY&type=video&q=${getQuery.input}`;
const [data, setData] = useState([]);
useEffect(() => {
async function fetchData() {
let request = await Axios.get(API_URL);
setData(request);
}
fetchData();
}, [API_URL]);
console.log(data);
return (
<div className="searchPage">
<div className="filter">
<TuneSharpIcon></TuneSharpIcon>
<h2>FILTERS</h2>
</div>
<hr></hr>
<ChannelRow
image="https://images.indianexpress.com/2022/01/Republic-Day_1200_AP2022.jpg"
channelName="Dummy"
verified
subs="670k"
noOfVideos={567}
desc="You can find awesome programming lessons here! Also, expect programming tips and tricks that will take your coding skills to the ..."
></ChannelRow>
<hr></hr>
{data?.data?.items?.forEach((item) => {
console.log(item.snippet.title);
console.log(item?.snippet.thumbnails.high.url)
console.log(item?.snippet.publishedAt)
console.log(item?.snippet.description)
console.log(item?.snippet.channelTitle)
return(<VideoRow
image={item?.snippet.thumbnails.high.url}
channelName={item?.channelTitle}
timestamp={item?.snippet.publishedAt}
title={item?.snippet.title}
desc={item?.snippet.description}
views="1.4M"
subs="1.4M"
></VideoRow>)
})}
</div>
);
}
export default SearchPage;
Change data?.data?.items?.forEach to data?.data?.items?.map. forEach returns nothing. So, even if you return the component from the callback, forEach will just ignore it. But, map will return all transformed results as an array.
You can read more about lists in react here.

Change state value in context file from child component?

Trying to understand context api, and I understand props are passed down. I am trying to change state of my Context file's value to another number like 50.
Created Context File
import React, { useState, createContext } from "react";
export const PointsContext = createContext();
export const PointsProvider = (props) => {
const [points, setPoints] = useState(0);**<--WANT TO CHANGE THIS**
return <PointsContext.Provider value={points}>{props.children}</PointsContext.Provider>;
};
Wrapped Everything In Provider in App.js
import {PointsProvider } from "./PointsContext";
<PointsProvider>
<ChildComponent>
</PointsProvider>
The "ChildComponent" is Provided Context
import React, { useState, useEffect, useContext } from "react";
import { PointsContext } from "../PointsContext";
const value = useContext(PointsContext);
return(
<Button title="ChangeNumber" onPress={() => Change value to 50 }/>
)
I figured it out, instead of importing
const value = useContext(PointsContext);
import this, which gives access to the setState in the context file. As long as you import this on to any screen you will have access to that useState to change stuff.
const [points, setPoints] = useContext(PointsContext);
the rest might go something like this!
<Button title="ChangeNumber" onPress={() => setPoints(50)}/>
<Text>{points}</Text>
This tutorial helped alot thanks devEd, he is one of my favs!
DevEd Youtube React State

how to set value in hooks

I have a problem with hooks in ReactJS
as you see here i defined a prop that should call from child component
but when i want to change the value by calling change component it doesn't work and my state doesn't set.
can someone help me?
don't forget to read the comments
import React, {useState} from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
const setSelectedCollection = (e) => {
setCollection(e);
console.log(e); // returns the true value
console.log(collection); // returns null
}
return(
<div>
<Collection onChoosed={(e) => setSelectedCollection(e)}/>
</div>
)
}
export default SingleReminderPage;
Use setState with a callback function
const setSelectedCollection = (e) => {
setCollection((state)=> {...state, e});
}
setCollection(e) - wont update the state immediately.
I want to Understand SetState and Prevstate in ReactJS
This might help you around, the useEffect will be called on each colletion update
import React, { useState, useEffect } from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
useEffect(() => {
console.log(collection)
}, [collection])
return (
<div>
<Collection onChoosed={(e) => setCollection(e)} />
</div>
)
}
export default SingleReminderPage;
it seems like the setCollection is called after the logging action to check something like that you can print the collection value on the component itself
import React, {useState} from "react";
import Collection from "./Collection";
import ReminderPeriod from "./ReminderPeriod";
function SingleReminderPage() {
const [collection, setCollection] = useState(null);
const setSelectedCollection = (e) => {
setCollection(e);
console.log(e); // returns the true value
console.log(collection); // returns null
}
return(
<div>
{collection}
<Collection onChoosed={(e) => setSelectedCollection(e)}/>
</div>
)
}
export default SingleReminderPage;

Context is not available right after page refresh in React

There's WarriorPage component which use context where is data I want to render. After page refresh, firstly I got an empty array from the context and only after a while I got array with my data. That causes error because I'm destructuring object from that array(which is empty in the start). Any sugestions?
WarriorPage
import React, { useContext } from 'react';
import { useParams } from 'react-router-dom';
import AllWarriorsContext from '../../contexts/AllWariorsContext';
export default function WarriorPage() {
let { identy } = useParams();
const { warriorsData } = useContext(AllWarriorsContext);
const {number, name, skill, description} = warriorsData[identy]; // got undefined here after page reload
return(...);
}
In Parent component
import React, { useEffect, useState, useContext } from 'react';
import AllWarriorsContext from '../../contexts/AllWariorsContext';
import WarriorPage from '../WarriorPage/WarriorPage';
export default function Parent() {
const [myWarriorsListContext, setMyWarriorsListContext] = useState([]);
useEffect( () => {
setMyWarriorsListContext(JSON.parse(localStorage.getItem('myWarriorsList')) || []);
},[]);
return(
<AllWarriorsContext.Provider value={{
warriorsData: allWarriorsData
}}>
<WarriorPage />
</AllWarriorsContext>
);
}

How to render an object of arrays with useEffect

I can't seem to get my object of arrays working. I want to pass an array from an api into a setstate function to turn that state into an array. Then iterate over that array. iterating should give me access to the object's properties. I want to access unique object properties to return and render them into my component. However, I get an error "Object Expected".
import React,{useState,useEffect} from 'react';
import './App.css';
import { CharacterComponent } from "../src/CharacterComponent"
import axios from "axios"
import ReactDOM from "react-dom";
export const Characters = () => {
// Try to think through what state you'll need for this app before starting. Then build out
// the state properties here.
// Fetch characters from the star wars api in an effect hook. Remember, anytime you have a
// side effect in a component, you want to think about which state and/or props it should
// sync up with, if any.
const [character,setCharacter] = useState({})
useEffect( () => {
axios.get("https://swapi.co/api/people")
.then(res => setCharacter(res.data.results) )
},[])
(console.log(character))
return (
<>
<div>
{character.map((element,index) => <CharacterComponent id={element} key={index} />)}
</div>
</>
)
}
That's weird, seems to be working fine in this sandbox: https://codesandbox.io/s/lingering-brook-veo3f
I initialized the state as an empty array as well:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import CharacterComponent from "./CharacterComponent";
import "./styles.css";
function App() {
const [character, setCharacter] = useState([]);
useEffect(() => {
axios
.get("https://swapi.co/api/people")
.then(res => setCharacter(res.data.results));
}, []);
return (
<div className="App">
{character.map(item => (
<CharacterComponent id={item} />
))}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Maybe take a look to see if there's something wrong with your child component:
import React from "react";
const CharacterComponent = ({ id }) => {
return <div>{id.name}</div>;
};
export default CharacterComponent;

Resources