request data from Github api - javascript

I wanted to import data(get users) from https://docs.github.com/en/rest/reference/users#list-users
the code in JS file(reactjs) is like
const { Octokit } = require("#octokit/rest");
const octokit = new Octokit();
async function myAsyncMethod() {
const result = await octokit.request("GET /users");
console.log(result.data);
}
myAsyncMethod();
but in the browser, didn't show anything, it's the correct way to get the data?

It all depends on where do you want to call this piece of code.
For instance, let's say that you need to call it as soon as the component that you're going to display is rendered. In that case, you will need to use the useEffect hook, and call your function from there.
See the following piece of code (I'm using the component App just for the example).
import React, { useEffect } from "react";
const { Octokit } = require("#octokit/rest");
export default function App() {
const octokit = new Octokit();
useEffect(() => {
getGithubUsers();
});
async function getGithubUsers() {
const result = await octokit.request("GET /users");
console.log(result.data);
}
return <></>;
}

Related

I got products in console in redux actions but When i use same funtion in component and try to get products by useselector hook i got undefined

This is an API call and in console, i get all products . But when I use the same getProducts function in components I got undefined in console
export const getProducts = ()=> async(dispatch)=>{
try {
const data = await fetch("http://localhost:80/api/products/getallproducts",{
method:"GET",
headers:{
"Content-Type":"application/json"
}
});
const res = await data.json();
console.log(res);
dispatch({type:"SUCCESS_GET_PRODUCTS",payload:res});
} catch (error) {
dispatch({type:"FAIL_GET_PRODUCTS",payload:error.response});
}
}
I use it on Home page and got undefined instead of products as i am using same function of getProducts
import React, { useEffect } from 'react'
import Categories from '../components/Categories'
import Banner1 from '../components/Banner1'
import MaterialUiaresoul from '../components/MaterialUiaresoul'
import ProductSlide from '../components/ProductSlide'
import FeaturedProducts from '../components/FeaturedProducts'
import { useDispatch, useSelector } from 'react-redux'
import { getProducts } from '../redux/actions/action'
const Home = () => {
const products = useSelector(state => state.getproductsdata);
console.log(products)
const dispatch = useDispatch();
useEffect(() => {
dispatch(getProducts());
}, [dispatch]);
return (
<>
<MaterialUiaresoul/>
<ProductSlide/>
<Banner1/>
<Categories/>
<FeaturedProducts />
</>
)
}
export default Home
You are trying to dispatch something that is not redux action.
Let's see, you are trying to call this line dispatch(getProducts());
After getProduct call, it will return a new async function, that doesn't called and expect dispatch to be passed in it.
Normally actions look like this:
export function addTodo(text) {
return { type: ADD_TODO, text }
}
Its just a function that return a plain object with type as a required property.
When dealing with api calls using redux, its better to look into some libraries that will help you, such as redux-thunk or redux-saga for example. Redux actions sync by default and async behavior can be reached with use of some middlewares.
In your example, you can make your code work as expected if you will run your getProduct function, and then run response from it with dispatch passed as first argument:
const dispatch = useDispatch();
const createApiCall = getProduct();
createApiCall(dispatch)
I'm still not sure whether it will work and recommend you to look at redux-thunk. Its pretty easy to learn and use.

Async function in UseEffect

I am trying to get data from AsyncStorage and eventually map this data to a list of buttons on my home screen. The data is saved to AsyncStorage from an API call that is made upon login.
In my async function, I am able to successfully retreive the data from AsyncStorage and parse it into JSON format, and then log it to the console. It looks like this:
{
1 : {title:"Timesheet",component_name:"Timesheet"}
2 : {title:"Personal Info",component_name:"PersonalInfo"}
3 : {title:"Employee Directory",component_name:"EmployeeListing"}
}
The problem I am running into is that I can't save this data to my useState variable and then render it into the component after useState is updated by my async function. Every time I try to access this data, I either get null or a Promise object. How can I access the data after useState is updated? Do I need to use a different React hook to call the Async function?
Here is the code that I am using:
import { Text, View, StyleSheet } from 'react-native';
import { useState, useEffect } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
export default function HomeScreen() {
const [buttonData, setButtonData] = useState(null);
useEffect (() => {
const loadHomeScreenButtons = async () => {
try {
const buttons = await AsyncStorage.getItem('app_screens').then(screens => {
// Parse the JSON data from its stored string format into an object.
let app_screens_json = JSON.parse(screens);
let app_screens_list = app_screens_json.app_screens;
console.log(app_screens_list); // This outputs the data to the console.
setButtonData(app_screens_list); // Trying to set the button data in useState.
return app_screens_list;
});
}
catch (e) {
console.log(e)
}
}
loadHomeScreenButtons();
}, [])
return (
<View style={home_styles.container}>
<Text>{buttonData[1]["title"]}</Text>
</View>
);
}
You just need to render a loading component until your data is fetched.
{ buttonData?.length?
<Text>{buttonData[1]["title"]}</Text> : <Text>...loading</Text>
}
You are getting an error as you are trying to access a property that does not exist at the render.
Try this way
const loadHomeScreenButtons = useCallback(async () => {
try {
const screens = await AsyncStorage.getItem('app_screens')
const app_screens_json = JSON.parse(screens)
setButtonData(app_screens_json.app_screens)
}
catch (e) {
console.log(e)
}
}, []);
useEffect(() => {
loadHomeScreenButtons();
}, [loadHomeScreenButtons]);

Firebase Storage Context with Storage Data

I am using Firebase and React and learning how to use React Contexts. I created a context that queries Firebase to get data from there (user's files URL's for example). The context works fine, however, I can't get the context to become asynchronous. I haven't seen any examples of this and am not sure if it's possible. My code is below.
StorageContext.js:
import React, { useContext, useEffect, useState } from 'react';
import { auth } from './FirebaseConfiguration';
import fire from './FirebaseConfig';
import { useAuth } from './AuthContext';
const StorageContext = React.createContext();
export function useStorage() {
return useContext(StorageContext);
}
export function StorageProvider({ children }) {
const { currentUser } = useAuth();
const [fileURLs, setFilesURL] = useState([]);
async function getUserData() {
var storage = fire.storage();
var storageRef = storage.ref(currentUser.uid);
storageRef
.listAll()
.then(function (result) {
result.items.forEach(function (imageRef, i) {
let temp = filesUploaded;
temp.push(imageRef.name);
setFilesUploaded(temp);
});
console.log(filesUploaded);
// console.log(getData(filesUploaded));
getData(filesUploaded);
})
.catch(function (error) {
console.log(error);
});
}
const value = { getUserData };
return (
<StorageContext.Provider value={value}>{children}</StorageContext.Provider>
);
}
Dashboard.js:
import React, { useState, useEffect } from 'react';
import { useStorage } from './Contexts/StorageContext';
export default function Dashboard() {
const { getUserData } = useStorage();
async function getData() {
await getUserData().then((data) => {
console.log(data);
});
}
useEffect(() => {
getData();
}, []);
return (
<div>
console.log('data');
</div>
The useEffect in Dashbaord.js runs fine, the problem is that getUserData() returns immediately even though it should be waiting until (and thus the .then((data) => { console.log(data) } is empty.
Is it possible to run a Context Asynchronously? Or is there another problem that I am missing?
Thanks
The reason it returns immediately is that you use then and not await. Rewrite your function to this and it should work:
async function getUserData() {
var storage = fire.storage();
var storageRef = storage.ref(currentUser.uid);
const result = await storageRef.listAll();
result.items.forEach(function (imageRef, i) {
let temp = filesUploaded;
temp.push(imageRef.name);
setFilesUploaded(temp);
});
console.log(filesUploaded);
// console.log(getData(filesUploaded));
getData(filesUploaded);
}

React hangs when trying to connect to component

For some reason, when trying to connect this component, react simply hangs without giving any error:
import React, { useState, useEffect } from 'react';
import { useHttp } from '../../hooks/http.hooks';
import _ from 'lodash';
import profileImg from '../../img/system/profile/profileImg.svg';
function ProfileLink() {
const { request } = useHttp(); // To get data
const [profile, setProfile] = useState({});
const profileID = JSON.parse(localStorage.getItem('user')).id;
function takeProfileLink() {
const userID = JSON.parse(localStorage.getItem('user')).id;
setProfile({
...profile,
link: `profile/${userID}`
});
}
async function takeProfile() {
const data = await request(`http://localhost:5500/api/auth/get/${profileID}`);
setProfile({
...profile,
picture: _.get(data, 'profile.picture', 'https://i.pinimg.com/originals/0c/3b/3a/0c3b3adb1a7530892e55ef36d3be6cb8.png'),
name: _.get(data, 'profile.name', '')
});
}
async function takeProfilePicture() {
if (profile.picture) {
return `http://localhost:5500/api/upload/image_get/${profile.picture}`;
} else {
return profileImg;
}
}
async function standProfilePicture() {
const link = await takeProfilePicture();
setProfile({
...profile,
pictureLink: link
});
}
useEffect(async() => {
await takeProfile();
takeProfileLink();
}, []);
standProfilePicture();
return (
<a href={profile.link} className="profile-link">
<div className="profile-name">
{profile.name}
</div>
<div className="profile-picture">
<img src={profile.pictureLink} alt="profile picture"/>
</div>
</a>
);
}
export default ProfileLink;
Presumably the problem is with the profile object. Previously, everything was packaged in variables and everything worked, but now I replaced the variables with an object and react just stopped loading.
Try moving the call to standProfilePicture() inside the useEffect hook. A dangling function call may be causing the component re-render indefinitely, thus freezing the page.

How to pass route params in Context API

I'm using the context API and I have this in my context file:
useEffect(() => {
async function getSingleCountryData() {
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/${props.match.alpha3Code.toLowerCase()}`
);
console.log(result)
setCountry(result.data);
}
if (props.match) getSingleCountryData();
}, [props.match]);
In the component I'm using, it doesn't work because it doesn't know what the props.match.alpha3Code is. How can I can pass the value? The alpha3Code is coming from the URL: localhost:3000/country/asa where asa is the alpha3Code, how can I get this value?
Basically, what I'm trying to do is. I have a list of countries I listed out on the home page. Now I'm trying to get more information about a single country. The route is /country/:alpha3Code where alpha3Code is gotten from the API.
FWIW, here is my full context file:
import React, { useState, createContext, useEffect } from 'react';
import axios from 'axios';
export const CountryContext = createContext();
export default function CountryContextProvider(props) {
const [countries, setCountries] = useState([]);
const [country, setCountry] = useState([]);
useEffect(() => {
const getCountryData = async () => {
const result = await axios.get(
'https://cors-anywhere.herokuapp.com/https://restcountries.eu/rest/v2/all'
);
setCountries(result.data);
};
getCountryData();
}, []);
useEffect(() => {
async function getSingleCountryData() {
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/${props.match.alpha3Code.toLowerCase()}`
);
console.log(result)
setCountry(result.data);
}
if (props.match) getSingleCountryData();
}, [props.match]);
return (
<CountryContext.Provider value={{ countries, country }}>
{props.children}
</CountryContext.Provider>
);
}
In the component I'm using the country, I have:
const { country } = useContext(CountryContext);
I know I can do this from the component itself, but I'm learning how to use the context API, so I'm handling all API calls in my context.
The API I'm making use of is here
Codesandbox Link
Project Github link
You can update the context from a component using it by passing down a setter function which updates the context state.
export default function CountryContextProvider({ children }) {
const [countries, setCountries] = useState([]);
const [country, setCountry] = useState([]);
const [path, setPath] = useState('');
useEffect(() => {
async function getSingleCountryData() {
const result = await axios(`your/request/for/${path}`);
setCountry(result.data);
}
if(path) getSingleCountryData();
}, [path]);
return (
<CountryContext.Provider value={{ countries, country, setPath }}>
{children}
</CountryContext.Provider>
);
}
Now use setPath to update the request endpoint with the route match once this component is mounted.
const Details = ({ match }) => {
const {
params: { alpha3Code }
} = match;
const { country, setPath } = useContext(CountryContext);
useEffect(() => {
setPath(alpha3Code);
}, [alpha3Code]);
return (
<main>Some JSX here</main>
);
};
export default withRouter(Details);
Linked is a working codesandbox implementation
In the component I'm using, it doesn't work because it doesn't know
what the props.match.alpha3Code is. How can I can pass the value? The
alpha3Code is coming from the URL: localhost:3000/country/asa where
asa is the alpha3Code, how can I get this value?
I guess the root of your problem is this one. You have no idea which the aplha3Code parameter comes from. I have dived into your GitHub repo to make it clearer.
First, match is one of react-router provided terms. When you use something like props.match, props.history, props.location, you must have your component wrapped by the withRouter, which is a Higher Order Component provided by react-router. Check it out at withRouter. For example, below is the withRouter usage which is provided by react-router:
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
render() {
const { match, location, history } = this.props;
return <div>You are now at {location.pathname}</div>;
}
}
const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
ShowTheLocation is wrapped by the withRouter HOC, which will pass all the route props (match, history, location...) to ShowTheLocation through props. Then inside ShowTheLocation, you are able to use something like props.match. Clear enough?
So back to your problem! You have not wrapped any components by withRouter yet, have you? Stick to it and have some fun! You will figure it out soon!
Also, please be aware that you must place your component under the BrowserRouter to be able to use the react-router things
If you want to go with Hooks, please take a look at this super useful one:
https://usehooks.com/useRouter/
It wraps all the useParams, useLocation, useHistory, and use useRouteMatch hooks up into a single useRouter that exposes just the data and methods we need. Then, for example, inside your component, do it like this:
import { useRouter } from "./myCustomHooks";
const ShowMeTheCode = () => {
const router = useRouter();
return <div>This is my alpha3Code: {router.math.params.alpha3Code}</div>;
}
Update 1 from Peoray's reply:
This is where the problem occurs:
https://github.com/peoray/where-in-the-world/blob/cb09871fefb2f58f5cf0a4f1db3db2cc5227dfbe/src/pages/Details.js#L6
You should avoid calling useContext() straightly like that. Have a look at my example below:
// CountryContext.js
import { useContext, createContext } from "react";
const CountryContext = createContext();
export const useCountryContext = () => useContext(CountryContext);
Instead, you should wrap it by a custom hook like useCountryContext above. And then, inside your Details component, import it and do like:
import React, from 'react';
import { useCountryContext } from '../contexts/CountryContext';
const Details = (props) => {
const { country } = useCountryContext();
...
}
Update 2 from Peoray's reply:
Although I have stated it in advance for you, I just feel like you did not make enough effort to go through what I said.
Also, please be aware that you must place your component under the
BrowserRouter to be able to use the react-router things
In your codesandbox, it shows the Cannot read property 'match' of undefined error. Okay, as I said above, you have not moved the ContextCountryProvider to under the BrowserRouter to get the useRouter work.
I have fixed it for you, and the screen popped out, please check it at updated codesanbox here. You will get what you need at App.js file.
Although it still throws some Axios bugs there, I think my job is done. The rest is up to you.
You might use useParams hook to get everything you need inside your context provider. Docs
Something like this:
import useParams in file where your Provider component is
in your CountryContextProvider add this at the top of the component:
const { alpha3Code } = useParams();
update useEffect which needs props.match
useEffect(() => {
async function getSingleCountryData() {
const result = await axios(
`https://restcountries.eu/rest/v2/alpha/${alpha3Code.toLowerCase()}`
);
console.log(result)
setCountry(result.data);
}
if (alpha3Code) getSingleCountryData(); // or if you need `match` - do not destructure useParams()
}, [alpha3Code]);

Categories

Resources