How to render an object of arrays with useEffect - reactjs

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;

Related

Why is the `question` property in the API not reachable and why is questionBank not rendering?

Just to let you know, I don't yet know how to use class based components, setState, etc. I also don't know how to use other things in async js like axios or whatever else yet. This is what I can do below. Very basic.
This is App.js:
import Questions from './components/Questions.js'
import './index.css'
import {React, useState, useEffect} from 'react'
function App() {
const [questions, setQuestions] = useState([])
useEffect(() => {
async function getQuestions(){
const response = await fetch("https://opentdb.com/api.php?amount=5")
const data = await response.json()
setQuestions(() => data.results)
}
getQuestions()
}, [])
const questionBank = questions.map(singleQuestion => {
<Questions
question={singleQuestion.question}
/>
})
console.log(questions[0].question)
return (
<div>
{questionBank}
</div>
);
}
export default App;
For some reason, console.log(questions[0].question) when typed in to the editor and saved for the first time, it shows a question from the api. But after refreshing the page it doesn't show a question but it says: App.js:44 Uncaught TypeError: Cannot read properties of undefined (reading 'question') But when I just do this: console.log(questions[0]), it shows the first object of the array from the API no problem. I'm confused.
Also, questionBank doesn't render at all for some reason.
This is Questions.js:
import React from 'react'
export default function Questions(props){
return(
<div>
<p>{props.question}</p>
<br />
</div>
)
}
This is index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
<App />
)
There are few things to improve in your code (such as maybe make a useCallback out of function getQuestions in the useEffect), but the biggest issue is that you are not properly returning JSX from the map method.
Your code:
const questionBank = questions.map(singleQuestion => {
<Questions
question={singleQuestion.question}
/>
})
notice the curly braces { & }. The proper code:
const questionBank = questions.map(singleQuestion => (
<Questions
question={singleQuestion.question}
/>
))
After this change, your code should work properly.
Also, your console.log will cause errors, because you are console.logging before even fetching theses questions, so obviously questions[0] is undefined.
More improvements to the code:
export default function App() {
const [questions, setQuestions] = useState([]);
const getQuestions = useCallback(async () => {
const response = await fetch("https://opentdb.com/api.php?amount=5");
const data = await response.json();
setQuestions(data.results);
}, []);
useEffect(() => {
getQuestions();
}, [getQuestions]);
const questionBank = questions.map((singleQuestion) => (
<Questions question={singleQuestion.question} />
));
return <div>{questionBank}</div>;
}

Why my useState from Context doesn't update

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}/>*/}

React.js - passing functions between components using Context API - not working

I am trying to pass a function between two components but even though I do not have any errors, the function that I am passing wont show or to be precise it is not working. I have two files and one of them is creating a context while the other is using it (obviously). Now, they are not shown in App.js (which is rendered in index.js, usual stuff) they are in the seperate folder. I am using React Router to show one the pages (News.js).
Here are the files:
NewsContext.js
import React, { useContext, createContext, useState, useEffect } from "react";
export const newsK = React.createContext();
export const NewsContext = (props) => {
const working = () => {
console.log("it is working");
};
return <newsK.Provider value={working}>{props.children}</newsK.Provider>;
};
export default NewsContext;
News.js
import React, { useContext, useState, useEffect } from "react";
import { newsK } from "./NewsContext";
import { NewsContext } from "./NewsContext";
const News = () => {
const data = useContext(newsK);
return (
<NewsContext>
<div>
<button onClick={data}></button>
</div>
</NewsContext>
);
};
export default News;
When i pressed the button, it wont do anything. Any tips?
You're trying to use context outside the NewsContext component
The solution for this will be to create a component that will call useContext inside NewsContext.
I.e.
const WrappedButton = () => {
const data = useContext(newsK)
return <button onClick={data} />
}
And then put it inside the NewsContext:
<NewsContext>
<div>
<WrappedButton />
</div>
</NewsContext>

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>
);
}

Merging two objects with useContext and state?

So i have this problem where it doesn't merge the two objects since refsContext is empty when useEffect gets called after render. It ends with only one of the refs in the object. useEffect(() => {setRef(something)}, [ref]); results in an infinite empty object loop. Did i miss something?
refs.context.jsx
import { createContext } from "react";
const refsContext = createContext({});
export default refsContext;
Same code over multiple files
/** #jsx jsx */
import React, { useContext, useEffect, useRef } from "react";
import refsContext from "../../context/refs.context";
const StackoverflowExample= () => {
const projectsRef = useRef(null);
const [ref, setRef] = useContext(refsContext);
useEffect(() => {
setRef({ ...ref, projects: projectsRef.current });
}, []);
return (
<section ref={projectsRef}></section>
);
};
export default StackoverflowExample;
App.jsx
import React, { useState, useEffect } from "react";
import { render } from "react-dom";
import Pages from "./Pages";
import { BrowserRouter } from "react-router-dom";
import refsContext from "./context/refs.context";
const App = () => {
//Default Contexts
const refsHook = useState({});
console.log(refsHook[0]);
//All my wrappers/providers for my App
return (
<refsContext.Provider value={refsHook}>
<BrowserRouter>
<Pages/>
</BrowserRouter>
</refsContext.Provider>
);
};
render(<App />, document.getElementById("root"));

Resources