I'm sorry if my question is too ridiculous, because I'm new to programming.
I created a project with React, I have 3 different components: navbar, sidebar and data.
I received json data from an api using hooks in my data component.
import { useEffect, useState } from "react";
export const Data = () => {
const [data, setData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setData(json));
}, []);
};
Now, how can I access the "data" state in the data component from other components?
I don't want to use Context api, because I've heard that it is only used in cases where the state affects all components, like authentication
thanks in advance for your help
I have added few lines in your codesandbox. I think this is same that you want to achieve
codesandbox
Thank you to everyone who helped me. Actually, I realized that the title is not correct. What I wanted to do was to use the data brought outside the component inside the component. I did this by creating custom hooks. If anyone is curious, I leave the code below.
import { useEffect, useState } from "react";
export default function useData(id = 1) {
const [data, setData] = useState([]);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
.then((response) => response.json())
.then((json) => setData(json));
}, []);
return { data };
}
Then I import and use the useData hook I created in any component.
(I'm not even sure it's called a hook.)
Example: const {data} = useData(4)
You could maybe use the module.exports function in the data component and then just call it in the necessary components. For example:
import { useEffect, useState } from "react";
export const Data = () => {
const [data, setData] = useState();
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setData(json));
}, []);
};
module.exports = data;
Then in the navbar component for example you call it and use it where it is necessary:
const Navbar = () => {
const data = require(../Data)
...
...
...
}
Hope it helps.
Related
I have a React component (also using TypeScript) that returns a photo to its parent component:
import React, { useEffect, useState } from "react";
import axios from "axios";
export const Photo = () => {
const [image, setImage] = useState<Image[]>([]);
// Backend API
const proxyUrl = "http://localhost:3001";
const api = "/photo";
interface Image {
src: string;
}
useEffect(() => {
(async function callAPI() {
axios
.get<Image>(proxyUrl + api)
.then((response) => {
setImage([
{
...response.data,
},
]);
})
.catch((error) => console.log(error));
})();
}, []);
if (image.length === 0) return <span>loading Image...</span>;
return <img src={String(image[0])} />;
The goal is to get an artist's profile picture from my backend. The only way that I can save the image in state is by using the spread operator, and when I do so, it SPREADS the URL - placing each taking each letter and placing it as a value in an object (see the screenshot below).
When I remove the spread operator, I get lots of errors. I need a way to retrieve the photo URL without breaking it up so that I can return and view it. Perhaps by changing the way I defined the interface? Or by setting up state differently?
Image of the URL being spread
first of all modify your useState like this :
const [image, setImage] = useState<String>([]);
and data is fetched you should setState like this :
setImage(response.data)
and delete Image from your get function type.
your return :
return <img src={image)} />;
With the help of the comments above by mortezashojaei, I was able to tweak the component and finally able to get it to work as intended. Adding the code here in case anyone's interested.
import React, { useEffect, useState } from "react";
import axios from "axios";
export const Photo = () => {
const [image, setImage] = useState<string>("");
// Backend API
const proxyUrl = "http://localhost:3001";
const api = "/photo";
useEffect(() => {
(async function callAPI() {
axios
.get(proxyUrl + api)
.then((response) => {
setImage(response.data);
console.log("RESPONSE.DATA");
console.log(response.data);
})
.catch((error) => console.log(error));
})();
}, []);
console.log("Image (state): ");
console.log(image);
if (!image) return <span>loading Image...</span>;
return <img src={image} />;
};
I'm a very beginner in React and Next.JS. I'm doing an app and I'm using the useContext hook. So, I have this code
import { createContext } from 'react';
let data;
fetch(API_URL)
.then(response => response.json())
.then(result => {
data = result.data;
})
.catch(error);
export const UserContext = createContext(data);
The problem is that when the context is created, the value of 'data' is null. Is there a way to do this asynchronously?
Something like this should do it:
import { useState, useEffect, createContext } from 'react';
const UserContext = ({children}) => {
const [data, setData] = useState();
const Ctx = createContext();
useEffect(() => {
fetch(API_URL)
.then(response => response.json())
.then(result => {
setData(result.data);
})
.catch(error);
}, []};
return (
<Ctx.Provider value = {data} >
{children}
</Ctx>
);
}
Didn't test it, but this should give you an idea; You can use it like
<UserContext>
// your code here
</UserContext>
A better way to do it would be to extract the fetch logic in a custom hook:
const data = useUserData(); // fetch logic here
<UserContext value={data}>
// your code here
</UserContext>
but since you are a beginner in React, I would keep it simple
Here is how I have created a Context for simple program I am writing
import React, { useState, createContext, useEffect } from "react";
export const PhotoContext = createContext();
export const PhotoProvider = (props) => {
const [photo, setPhoto] = useState([]);
useEffect(() => {
console.log("Use Effect Runs HAHAHAH");
console.log("HAHAHAHAHAHAHAH");
fetchPhotos();
async function fetchPhotos() {
const url =
"https://raw.githubusercontent.com/bobziroll/scrimba-react-bootcamp-images/master/images.json";
fetch(url)
.then((res) => res.json())
.then((arr) => {
setPhoto(arr);
})
.catch(console.log("ERROR"));
}
}, []);
return (
<PhotoContext.Provider value={[photo, setPhoto]}>
{props.children}
</PhotoContext.Provider>
);
};
There is another file where I want to load the data in the photos variable. Here is the code for it. I have used setTimeout to see where exactly is the problem. It seems whenever the statement in setTimeout runs, the value in console in returned twice. First, it is empty and the second has the actual value. But since, I try to access the photos.url, and since the first time it is undefined, the program collapses.
import React, { useState, useContext } from "react";
import { PhotoContext } from "../Context/PhotoContext";
const Photos = (props) => {
const [photos, values] = useContext(PhotoContext);
setTimeout(() => {
console.log(photos[0].url);
}, 3000);
return <div>{}</div>;
};
export default Photos;
Help would be really appreciated.
Didn't see the problem. I created sandbox for your example.
https://codesandbox.io/s/inspiring-lovelace-5r1gb?file=/src/App.js
I have a MERN Web-app, which I am learning React Hooks.
What I am trying to do : Access the states in my Redux.
When i refresh the page,
The error : TypeError: Cannot read property '_id' of null
I am not able to access it when I clearly see the states in my redux developer tools.
I have tried console.log(auth.isAuthenicated) but it returns null. However, when I do console.log(auth), it returns [object,object]. Which confuses me because I can't get inside.
Currently, I am researching and will look into react-persist. I was wondering if anyone can help me with my issue without react persist or explain why it might be a good idea to use it.
My redux :
token(pin):"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlNDFmYTNhOWIwZjk0NmU5N2Q5MmY4MiIsImlhdCI6MTU4Mzk0NzA5MSwiZXhwIjoxNTgzOTUwNjkxfQ.pysX20n4cxKK5NqcXPosIejSvCN3pbcSNpQvEOX9kBE"
isAuthenticated(pin):true
isLoading(pin):false
_id(pin):"5e41fa3a9b0f946e97d92f82"
name(pin):"admin"
email(pin):"admin#gmail.com"
date(pin):"2020-02-11T00:50:02.183Z"
__v(pin):0
snippets of my code :
import React, { useState, useEffect } from "react";
import { TiDelete } from "react-icons/ti";
import Restaurants from "../Restaurant/Restaurants";
import NutritionalGraphs from "../D3Graphs/NutritionalGraphs";
import { connect, useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { addItem, deleteItem } from "../../../actions/itemActions";
import IngredientsPredictions from "../Predictions/IngredientsPredictions";
import { loadUser } from "../../../actions/authActions";
import { createSelector } from "reselect";
const UserProfile = props => {
const dispatch = useDispatch();
const [newUserFavorite, setNewUserFavorite] = useState("");
const [favArray, setFavArray] = useState([]);
const tokenRecognized = useSelector(state => state.auth.token);
// const userID = useSelector(state => state.auth.user._id);
const auth = useSelector(state => state.auth);
const userStates = createSelector();
// name
// name => props.auth.user.name,
// userID => props.auth.user._id
// foodFavoritesArray => foodFavoritesArray.state.item.items
useEffect(() => {
dispatch(loadUser(tokenRecognized));
// console.log(userStates.userID);
console.log(auth.isAuthenicated);
axios
// .get(`/api/items/item/${userStates.userID}`)
.get(`/api/items/item/${auth.user._id}`)
.then(res => {
return res.data;
})
.then(json => {
setFavArray(json);
})
.catch(err => console.log(err));
}, [userStates.userID]);
console.log(favArray);
it is breaking at : .get(`/api/items/item/${auth.user._id}`):
Big thank you for the read.
You need to wait for your loadUser action to complete before you can access the data. I assume that it makes an async request. You need to that in two steps:
useEffect(() => {
// fetch user data when component mounts
dispatch(loadUser(tokenRecognized));
}, []);
useEffect(() => {
// check if user has been fetched (will not be the case on mount)
if (auth.user) {
axios
.get(`/api/items/item/${auth.user._id}`)
.then(res => {
return res.data;
})
.then(json => {
setFavArray(json);
})
.catch(err => console.log(err));
}
}, [auth.user]); // perform this when `auth.user` changes
I'm trying to use my custom hook inside the callback logic like this:
import React, { useEffect, useState } from 'react';
import useDataChange from '../../hooks/useDataChange';
const SomeComponent = () => {
return (
<Table
handleTableChange={data => useDataChange(data)}
/>
);
};
export default SomeComponent;
And my custom hooks (just to simplify) looks like that:
const useDataChange = data => {
console.log(data);
};
export default useDataChange;
In short, custom hook supposed to be fired when data from table is changed (ie. when handleTableChange in Table component is fired). Instead I'm getting:
React Hook "useDataChange" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
How can I use it when table data is changed?
The key to understanding hooks is to extract pieces of react code out of components. So your first step would be to get it working inside the component
const SomeComponent = () => {
const [data, setData] = useState([])
return (
<Table
handleTableChange={setData}
/>
);
};
Based on your code, I'm not seeing where you'd need a hook or side effect. But let's pretend that you do want to run some simple side effect:
const SomeComponent = () => {
const [data, setData] = useState([])
const [modifiedData, setModifiedData] = useState([])
useEffect(() => {
//here we're just going to save the current data stream into a new state variable for simplicity
setModifiedData(data)
}, [data])
return (
<Table
handleTableChange={setData}
data={modifiedData}
/>
);
};
So now we have some logic that runs a side effect. Now you can extract it to its own hook.
const useModifiedData = (data) => {
const [modifiedData, setModifiedData] = useState(data)
useEffect(() => {
setModifiedData(data)
}, [data])
return modifiedData
}
const SomeComponent = () => {
const [data, setData] = useState([])
const modifiedData = useModifiedData(data)
return (
<Table
handleTableChange={setData}
data={modifiedData}
/>
);
};
Here you have a hook that lives outside the component logic, so it can now go in its own file and be used across your project.
Like it says React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks. React has this limitation so that it can track the state and effects. In your case you can define you custom hook to return a function which does the desired work, instead of directly doing it in your hook.
In this case your custom hook file will look something like this-
const useDataChange = () => data => {
console.log(data);
};
export default useDataChange;
Then in your component you can use it like this -
import React, { useEffect, useState } from 'react';
import useDataChange from '../../hooks/useDataChange';
const SomeComponent = () => {
const callback = useDataChnage();
return (
<Table handleTableChange={callbackdata} />
);
};
export default SomeComponent;