Passing data/variables from parent to child in ReactJS Hooks - reactjs

i am looking to pass the json data that i received using the fetch API and use in the Useraccount component.
i have looked around and i can find a lot of material related to passing from child to parent and very few that mention from parent to child.
I have tried using this userinfo={credentailverify} and clearly it is not working for me, any suggestions please
Update3:
i have upload the small clip for the issue that i am facing for better understanding. i have tried to make the code very simple but still cant understand the reason why loginscreen is showing before showing the user account information.
youtube link showing issue
import Useraccount from "./Useraccount";
function Signin({ userinfo1, userinfo2 }) {
//userinfo1 is having customer account information
//userinfo2 is Boolean and showing if user is looged in or not if not then go to login page
return (
<div>
{userinfo2 ? (
<Useraccount userinfo={userinfo1} />
      ) : (
<SigninOptions />
      )}
    </div>
  );
}
export default Signin;
Update2: i am also experience one strange thing as when i set setUserinfo and pass the new state into the child it does show the new state in child component there but here in main code if i try to console the userinfonew after its set it is showing me the initial state as empty array, is it some thing i am missing here!!
.then((data) => {
setUserinfo(data.data)
console.log(userinfonew)
}
-Note i can see if i run console.log(userinfonew) outside the Async function then it does show the updated status but not inside the async function, although i am updating the status inside the Async function. cant understand the reason behind it
Update1: initial problem is solved thanks and i have updated the code, now the only issue i am facing is the condition that i am using in the return statement is both getting executed i.e first for few seconds < SigninOptions /> component and then the correct one as per the logic < Useraccount userinfo={userinfonew} /> component not sure if there is a delay somewhere or code is runnig twice
function Signin() {
const [siginalready, setifsignedin] = useState(false);
const [userinfonew, setUserinfo] = useState([]);
useEffect(() => {
credentailverify();
}, []);
let url = "http://localhost:5000/api/verifyifloginalready";
let options = {
credentials: "include",
method: "POST",
};
let verifyifloginalready = new Request(url, options);
let credentailverify = async () => {
const x1 = await fetch(verifyifloginalready)
.then((res) => {
if (res.status == 400 || res.status == 401) {
return setifsignedin(false);
} else {
setifsignedin(true);
return res.json();
}
}).then((data)=>
{
// here the console is shoewing empty array
setUserinfo(data.data)
console.log(userinfonew)
})
.catch((err) => console.log("err"));
return x1;
};
return (
<div>
// here first <SigninOptions /> renders for a SECOND and then <Useraccount userinfo={userinfonew} />
{siginalready ? (
<Useraccount userinfo={userinfonew} />
) : (
<SigninOptions />
)}
</div>
);
}
export default Signin;
the below is the code at the user account,
import React, { useState, useEffect } from "react";
import "../App.css";
function Useraccount({ userinfo }) {
return <div>{ `The user email address is ${userinfo}`}</div>;
}
export default Useraccount;
and after the data is passed to the child component how can i use it, i have seen one place mentioned to use as this.props.userinfo but i am using React Hook so cant use this method to access.
Thanks in advance.

You need to access the props passed to child:
function Useraccount({ userinfo }) {
if (!userInfo) return <div />
return <div>{`The user email address is ${userinfo}`}</div>;
}
Also use a template string like I did above

My recommendation is to track the response of your response in the state, then pass that state value into the child component.
It can be helpful to think of an effect as happening in a different execution than your main code. Any data inside of there can only be communicated to your component through the functions that you pass in as the effect dependencies.

Related

How to make setting state with useEffect() to run on page refresh?

My code is not long or complicated at all. It's simple. so please read!
(Im using react + next.js)
In the root file, app.js, I have useEffect to fetch photo data. This data array will be used in a page component so I pass it down from app.js via <Component.../>
function MyApp({ Component, pageProps }) {
const [photoData, setPhotoData] = useState([]);
const [user, setUser] = useState([]);
useEffect(() => {
const getPhotos = async () => {
try {
const photoData = await axios.get(
"https://jsonplaceholder.typicode.com/albums"
);
setPhotoData(photoData.data);
} catch (error) {
console.log(error);
}
};
getPhotos();
}, []);
useEffect(() => {
//code for finding user. no external api used.
setUser(user);
}
}
}, []);
const passedProps = {
...pageProps,
photoData,
user
};
return (
...
<Component {...passedProps} />
)
Then I pass the data (photodata) from a Home component to a (app.js 's) grandchild component, an Photo component
export default function Home({ photoData, user }) {
return(
<Photo photoData={photoData} user={user} />
)
In Photo component, I am receiving photoData and trying to set a state for photoArr with the default state of photoData.
When the entire app is first loaded, the photoData is passed down to the Photo component successfully that it sets the state without any issue.
But the main problem is that when I am in the Photo page (photos are loaded) and refresh the page, then it does not set the state for photoArr with photoData. Even though I can console log photoData received from app.js, it does not set state, photoArr, with the default state, photoData.
export default function Photo({ photoData, user }) {
const [photoArr, setPhotoArr] = useState(photoData);
//I have this as state because I change this array
//later on in this component (doing CRUD on the photo array).
console.log(photoData); // this returns the array received from app.js
console.log(photoArr); // []. returns an empty array
console.log(user); // returns the user object received from app.js.
return (
<div>
{photoArr.length > 0 ?
.... code mapping photoArr
: "Data is empty" //It returns this comment when I refresh the page
}
</div>
)
As you can see above, when I refresh the page, I get "Data is empty" meaning photoArr was not set even with the given default state. If I keep refreshing the page multiple times, it still shows a blank page.
From my research, it's due to setting state being asynchronous? So then how can I fix this problem?
Try this:
(In your Photo page)
const [photoArr, setPhotoArr] = useState(null);
useEffect(() => {
if(photoData.length) setPhotoArr(photoData) // If not empty, set the Arr
},[photoData]} // We listen to photoData's change
On page load, there aren't any data in your photoData, and as it pass down to Photo component, react remembers that state.
But with useEffect listen to photoData's change, we can setPhotoArr once the getPhotos function got the data back.

My react component never displays the information from the database

I have a small web app displays game information.
I am using React hooks so that the component is modern.
When this component loads, I want it to connect to the api via axios, and get the description of the game.
But when it loads, the value inside the <GameVault /> is always null.
When I look in the database, it is not null. If I hit the api directly, it does return the game description.
My console.log is hit twice for some reason. The first time it's null, the second time it has the needed value.
I am also not getting any errors, so I don't know why this isn't working.
Here is the code:
const Vault = ({ game }) => {
const [gameText, setGameText] = useState(null);
async function fetchGameText() {
const response = await axios.get(`/api/gamermag/${game.id}/gameDescriptionText`);
setGameText(response.data);
}
useEffect(() => {
fetchGameText();
}, []);
console.log("gameText: ", gameText);
const gamerValue = useMemo(() => {
return gameText ? gameText : "";
}, [gameText]);
return (
<GameVault value={gamerValue} />
)
}
export default Vault;
Is there a way to get this to work?
Thanks!
You need to wait for the data to load from the server. While the data is being fetched, gameText will be null and when it's done fetching, it stores the response. That is why your console.log hit twice. The first time is the component's first render, and the second time is when the gameText changes its state which caused a rerender.
You need to add logic to wait for the data.
if(!gameText){
return <div>loading...</div>
}

How to properly passing data through functional component in ReactJS?

I am new to react and this is very confusing to me. Any help would be appreciated.
So I have an Axios Interceptor, making sure the user is authenticated, but that not the issue, the issue is the ".then()" part of the interceptor. So I am trying to pass "res" into my functional component "Profile" like below.
export function GetProfiles(history) {
axiosInstance(history)
.get('/profile')
.then((res) => <Profile userData={UserProfile(res)} />)
.catch((err) => console.log("err", err));
}
So this is how to write my "UserProfile(res)" function
function UserProfile(props) {
let data = {
firstName: props.data.firstName,
lastName: props.data.lastName,
email: props.data.email,
phone: props.data.phone,
};
return { data };
}
export default UserProfile;
If I do console.log(data) in "UserProfile" I get all the data I needed. So everything is working as intended. However, when I try to retrieve those same data in the "Profile" component I get "undefined". So this is how I write my "Profile" component
function Profile({ userData }) {
console.log(userData);
}
export default Profile;
Again, any help would very much appreciate, I am new to this so there is a very big chance I am doing it wrong. Please point me in the right direction.
When you are fetching data from an API, normally you'd assign the response (res) to a variable, that way you separate the View (The component structure) from the Data (The user info from the API). So, in your case, you'd have to:
Define a variable to store the user data.
After that, inside the getProfile function, assign the response to the variable.
And finally, pass the variable as a prop to your component.
You can use this code as an example:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [profileData, setProfileData] = useState();
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'yourapiurl/profile',
);
setProfileData(result.data);
};
fetchData();
}, []);
return (
<>
<Profile userData={profileData} />
</>
);
}
export default App;
In this example, I'm using React Hooks, so you do your API call inside the useEffect hook. I defined a variable called profileData, where I will store the data from the API. Inside the fetchData function, I call the method setProfileData, so all the data that you got from the API will be stored inside the profileData variable. Finally, you pass the profileData as a prop to your Profile Component, and it will update as soon as the data is fetched from your API.
I got all the information from this link:
https://www.robinwieruch.de/react-hooks-fetch-data
In case you are using Class Components and not React Hooks, the process is very similar, just instead of defining the variable like this:
const [profileData, setProfileData] = useState();
You'd have to define it as the state of your component:
state = {
profileData: []
}
More info about how to fetch data from an API using Axios in React Class Components in the following link:
https://www.digitalocean.com/community/tutorials/react-axios-react
I hope this info was useful.
Happy Hacking!
I think you're trying to write UserProfile as a helper function but instead it looks like a function component the way you have it. You could map data in the .then chain before passing it down to your Profile component i.e.
let userData = userProfile(res);
return <Profile userData={userData} />

React: I have an api fetch and the data stores into my hook state. Why can I console.log the hook object, but not access it?

I have two other useEffects in my code that fetch data, update a state hook, and allow access to all data properly in other components/same component.
I have one useEffect, however, that's grabbing data from an api fetch that uses an authorization header. I've done this before, with no issue, but on the one in question, it gets the data, updates my state hook, and I can even console.log it out in another component, but the moment I try to do something with it, it gives me an error.
UseEffect:
useEffect(() => {
const claimStudents = async() => {
const url = "http://127.0.0.1:8000/api/TaughtStudents";
const result = await axios(url, {
headers: {
Authorization: `JWT ${localStorage.getItem("token")}`,
}
})
getState.updateClaimedStudents(result.data)
}
claimStudents()
}, [])
Error:
console error
Component that is calling my state data:
function ClaimedStudents() {
const getState = useContext(UserContext)
console.log(getState.claimedStudents)
return (
<Card>
<Card.Text>
</Card.Text>
</Card>
);
}
export default ClaimedStudents;
Console log that shows my data loading, though with a delay:
Console.log showing data
I know it's something to do with promises and/or the data not delivering in the right time, but I have had little luck googling this issue for an answer.
Any insight or points in the right direction of where I can help fix this would be appreciated.
I think you need to add a request status observable, like isLoadingStudents, it should be true while fetching the data and false otherwise, then add a spinner or something in the component if the isLoadingStudents is true.
if (isLoadingStudents) {
return <Spinner/>
}
Or you can directly go with this:
Warning: You cannot do custom error handling
getState? (
getState.claimstudent.map(({student}=>{
<li> {student} </li>
}))
):(
<Loader />
)
So turns out I was a goof and did the wrong thing inside my useState() hook. Whoops me. It didn't fix my data being not accessible 100%, but I'm no longer getting the error.

Can't render data from API being passed down as props (ReactJS)

I'm really stuck in trying to render some data being passed down as props. I'll include some code and definitions below, but if you feel that I need to include some further code snippets, please let me know (I'm really struggling to find what's causing the error, so I may have missed out the causal issue!).
I first take data from an API which is then used to populate a UserList component via useState (setUsers(data):
useEffect(() => {
async function getUserList() {
setLoading(true);
try {
const url =
"API URL";
const response = await fetch(url);
const data = await response.json();
setUsers(data);
} catch (error) {
throw new Error("User list unavailable");
}
setLoading(false);
}
getUserList();
}, []);
If a user is clicked in the UserList, this changes the selectedUser state of the parent Home component to be the specific user's unique_ID via:
onClick={() => setSelectedUser(unique_ID)}
If the selectedUser changes, the Home component also does a more updated data fetch from the API to get all information relevant to the specific user via their unique_ID:
useEffect(() => {
async function getSelectedUserData() {
try {
const url = `API URL/${selectedUser}`;
const response = await fetch(url);
const data = await response.json();
setSelectedUserData(data);
} catch (error) {
throw new Error("User data unavailable");
}
}
getSelectedUserData();
}, [selectedUser]);
The specific user data is then passed down as props to a child UserInformation component:
<UserInformation selectedUser={selectedUser} selectedUserData={selectedUserData} />
At this point, I can see all the data being passed around correctly in the browser React Developer Tools.
The UserInformation component then gets the data passed via props:
import React, { useEffect, useState } from "react";
function UserInformation({ selectedUser, selectedUserData }) {
const [currentUser, setCurrentUser] = useState({ selectedUserData });
useEffect(() => {
setCurrentUser({ selectedUserData });
}, [selectedUser, selectedUserData]);
return (
<div>
<p>{selectedUserData.User_Firstname}</p>
<p>{currentUser.User_Firstname}</p>
</div>
);
}
export default UserInformation;
And here is where I get stuck - I can't seem to render any of the data I pass down as props to the UserInformation component, even though I've tried a few different methods (hence the <p>{selectedUserData.User_Firstname}</p> and <p>{currentUser.User_Firstname}</p> to demonstrate).
I'd really appreciate any help you can give me with this - I must be making an error somewhere!
Thanks so much, and sorry for the super long post!
I managed to solve this (thanks to the help of Mohamed and Antonio above, as well as the reactiflux community).
import React from "react";
function UserInformation({ selectedUserData }) {
const currentUserRender = selectedUserData.map(
({ User_Firstname, User_Lastname }) => (
<div key={unique_ID}>
<p>{User_Firstname}</p>
</div>
)
);
return (
<div>
{selectedUserData ? currentUserRender : null}
</div>
);
}
export default UserInformation;
As selectedUserData was returning an array instead of an object, I needed to map the data rather than call it with an object method such as {selectedUserData.User_Firstname}.
const currentUserRender = selectedUserData.map(
({ User_Firstname, User_Lastname }) => (
<div key={unique_ID}>
<p>{User_Firstname}</p>
</div>
)
);
The above snippet maps the selected data properties found inside selectedUserData ({ User_Firstname, User_Lastname }), with the whole map being called in the return via {selectedUserData ? currentUserRender : null}.
Hopefully my explanation of the above solution is clear for anyone reading, and a big thanks again to Mohamed and Antonio (as well as a few others in the reactiflux Discord community) for helping!
You're trying to set the current user to an object with key "selectedUserData".
So if you want to access it you've to access it by this key name so change this line currentUser.User_Firstname to currentUser.selectedUserData.User_Firstname

Resources