React Hook Initializing the state with server call - reactjs

Working with a react component using hooks. I am attempting to assign values to my state after an Axios call. The data is correctly returned and it appears the state is correctly updated; however, the DOM is not updating with the values. Is this the proper method for doing this?
export const Main = (props) => {
const { token } = useParams()
const [user,setUser] = useState({name:""})
useEffect(()=>{
const getUser = async() =>{
const response = await API.post("usrinfo",{token:token})
setUser({name:response.data.name});
}
getUser()
},[token])
return(
<div className="main-header">{user.name}</div>
);
}

Found the issue:
AXIOS returns a data portion in it's response so instead of response.data.name it should be response.data.data.name.
Thanks for all your responses.

Related

React's new use() hook falls into infinite loop

I'm trying to load data for a client component. I can't use await/async as specified by React's RFC about use() hook. Thus I need to use use() hook.
However, it goes into infinite loop.
Here's my code:
import { use } from 'react'
const Component = () => {
const response = use(fetch('some_url'))
const data = use(response.json())
return <div>{data}</div>
}
Based on my intuition, I tried to use a callback inside the use() hook, as we do for useEffect():
const response = use(() => fetch('use_url'), [])
But it complained that an invalid parameter is passed into the use() hook.
I can't find anyting online. What should I do? What have I done wrong?
You need to "stabilize" the return of fetch. You could memoize it
const Component = () => {
const fetchPromise = React.useMemo(() => fetch('some_url').then(r => r.json()), [])
const data = use(fetchPromise);
return <div>{data}</div>;
}
I guess you just wanna memorized use result.
const response = useMemo(() => use(use(fetch('some_url')).json()), ['some_deps'])

Trying to pass an array to another component that I'm receiving through an async function

Essentially I have a page where I map out a list of files and after the user is down I call them from an api. I then package the file with other meta data. However my issue is that when I pass back my package to my frontend I am getting an error about passing back a promise. I'm using await on async function I know this is causing a promise to be passed to my variable but I am unsure how else to pass back my file with its meta data. Any suggestions for different approaches or a more proper way to use async functions in order to achieve my goal?
Code:
const gatherFileNames = async() =>{
let fams = defineFams()
let finishedCells = []
finishedCells = await QueryFiles(fams)
return finishedCells
}
export default async function GenerateGraphPage(){
let allCells = await gatherFileNames()
return(
<div>
<DefineHeader />
<CellGraph cells = {allCells}/>
</div>
);
}
Notes:
finishedCells is holding an array of objects
Completed Code for reference:
export default function GenerateGraphPage(){
const [data, setData] = useState();
useEffect(()=>{
const getData = async() => {
const fileData = await gatherFileNames()
setData(fileData)
console.log(fileData)
}
getData()
},[])
return(
<div>
<DefineHeader />
<CellGraph cells={data}/>
</div>
);
}
Assuming QueryFiles returns a promsie this might be what you are looking for, I also refactored your code a little bit, I hope you don't mind.
const gatherFileNames = () =>{
return QueryFiles(defineFams())
//no async
}
If someone knows how the async works in this example feel free to copy this answer to explain it. Because I don't know the technical terms but this worked for me.
export default async function GenerateGraphPage(){
let allCells = await gatherFileNames()
//async
return(
<div>
<DefineHeader />
<CellGraph cells={allCells}/>
</div>
);
}
I would also recommend using useState and a useEffect hook to call gatherFileNames so it isn't called on every render which could slow your website down.
export default async function GenerateGraphPage(){
const [data, setData] = useState();
useEffect(() => {
let FileData = [];
const getData = async () => {
//to use await in a useEffect you will need to make an async function
// and call it first in the useEffect
fileData = await gatherFileNames();
}
getData();
// getData called here before handling any other synchronous logic
setData(fileData)
}, []) //this empty array means this useEffect will run once when the page loads
//if you put 'dependencies here such as [data,setData]'
//this will run everytime data and setData are used
return(
<div>
<DefineHeader />
<CellGraph cells={data}/>
// using data here
</div>
);
}

After useEffect API call, state set by useState for json data being passed to a component as props returns empty array

I'm still a beginner in React and I'm trying to use useEffect to fetch data from an API and then useState to set the state and then pass that state as props to a child component.
But in my child component, it appears as an empty array each time when I do console.log. I understand that on the first render the state of my initial state is an empty array []. But I've been trying to combat this and send the right JSON data but can't seem to do so.
I am trying to do this as I have multiple child components that I wanna send data to.
Below is a workaround I coded up with some digging around but doesn't work either:
const api = 'url string'
const [races, setRaces] = useState([]);
const [races2, setRaces2] = useState([races]);
useEffect(() => {
fetch(api)
.then((resp) => resp.json())
.then((response) => setRaces(response));
}, []);
useEffect(() => {
if (races.length) setRaces2(races);
}, [races]);
<Child data={races2}
But this does not seem work to work either when I do console.log(props.data) in the child component.
This is how normally one would fetch data and try and send the data but in both cases, it's been the same.
const api = 'url string'
const [races, setRaces] = useState([]);
useEffect(() => {
fetch(api)
.then((resp) => resp.json())
.then((response) => setRaces(response));
}, []);
<Child data={races}
Following is a rough flow diagram explaining what I wanna do:
Thank you for your help in advance.
I made this quick example.
Here is what the code does:
Fetching the Data using UseEffect
Storing into State
Passing the State into Component as Props
Fetching the Props and Displaying the data.
Code for App.js
import "./styles.css";
import ChildComponent from "./ChildComponent";
import { useEffect, useState } from "react";
export default function App() {
const [title, setTitle] = useState(null);
// * Init on Page Load
useEffect(() => {
fetchTitle();
}, []);
const fetchTitle = async () => {
const response = await fetch(
"https://jsonplaceholder.typicode.com/posts/1"
);
const data = await response.json();
setTitle(data.title); //Setting the response into state
};
return (
<div className="App">
<ChildComponent data={title} />
</div>
);
}
Code for ChildComponent.js
export default function ChildComponent({ data }) {
return <div>{data}</div>;
}
I created this Codesandbox. This might help.
https://codesandbox.io/s/elegant-lumiere-cg66nt
Array and object are referential data types, passing as array dependency will not re-run side effect. useEffect dependencies should be primitive data type (string, number, boolean,undefined or null).
useEffect(() => {
if (races.length) setRaces2(races);
}, [races.length])// Dependencies must be primitive data type not referencial.

React Firebase read data results in too many renders

I'm using Firebase realtime database for my react project. I try to follow the firebase documentation and use "onValue()" to retrieve data. Here is my code:
export default function Home() {
const {currentUser} = useAuth();
const [userinfo,setUserinfo] = React.useState();
const uid = currentUser.uid
const db = getDatabase();
onValue(ref(db,`users/${uid}`),snapshot=>{
const data = snapshot.val();
setUserinfo(data);
})
console.log(userinfo);
return (
<main id="home">
<Hero />
</main>
)
}
This would result in an error of too many re-renders. I don't know how to retrieve the data. If I use
onValue(ref(db,`users/${uid}`),snapshot=>{
const data = snapshot.val();
console.log(data);
})
then the proper data would print out in the console perfectly fine. I also tried the following:
let info;
onValue(ref(db,`users/${uid}`),snapshot=>{
const data = snapshot.val();
info = data;
})
console.log(info)
but info would just be undefined. I can't seem to figure out the problem here. How can I use the data?
It throws error too many re-renders because you are not using any lifecycle hook or function to update/change state value and once you update your state it will again re-render your whole component and then again you update the state and the same thing happens in the loop causing too many re-renders.
So to avoid this you need to put code that is responsible for listening to changes from DB and changing state inside a block which will only get called on specific events or function calls or etc.
In your case, I suggest using useEffect hook. see below code -
export default function Home() {
const { currentUser } = useAuth();
const [userinfo, setUserinfo] = React.useState();
const uid = currentUser.uid
const db = getDatabase();
// this useEffect will get called only
// when component gets mounted first time
useEffect(() => {
// here onValue will get initialized once
// and on db changes its callback will get invoked
// resulting in changing your state value
onValue(ref(db, `users/${uid}`), snapshot => {
const data = snapshot.val();
setUserinfo(data);
})
return () => {
// this is cleanup function, will call just on component will unmount
// you can clear your events listeners or any async calls here
}
}, [])
console.log(userinfo);
return (
<main id="home">
<Hero />
</main>
)
}
Note - I have not worked with firebase real-time DB recently but by looking at the code and error I have added this answer, let me know if anything needs correction.

Return data from Async function React Native Redux

I am having trouble with accessing the data after fetching it with SecureStore in Expo for react-native.
Here is the simple code:
const infoofuser = SecureStore.getItemAsync('userInfo').then(value =>
console.log(`this is the vlaue from infouser: ${value}`),
);
console.log(`infoouser: ${JSON.stringify(infoofuser)}`);
the first infoofuser constant definition returns the object of the intended data.
console.log(`infoouser: ${JSON.stringify(infoofuser)}`);
however returns {"_U":0,"_V":0,"_W":null,"_X":null} which U understand is a promise. I would like to simply get the data that comes from the SecureStore call and use it to set my initialState in redux.
const infoofuser = SecureStore.getItemAsync('userInfo').then(value =>
value
);
this does not work either to access the data
You can use async method using async/await. Try this:
const userInfo = useSelector(state => state.userInfo);
const getData = async () => {
try {
const infoofuser = await SecureStore.getItemAsync('userInfo');
console.log('infoofuser:', infoofuser)
/// strore on redux
} catch (err) {
// handle error
}
}
useEffect(() => {
getData()
}, [])
if (!userInfo) return null
//render something else
You can check the Expo Secure Store docs for reference.

Resources