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
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'])
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>
);
}
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.
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.
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.