I've been trying to figure out how to access the promise value passed back from the POST request, but so far the solutions I've seen on here I can't get my head round how to implement in a functional component not using .then.
I've tried .stringify and .text , but no difference. It's still only console logging the promise.
Button.jsx
import React, { useState } from 'react';
import axios from 'axios';
import getResponse from '../Handler/getResponse.jsx'
import getToken from '../Handler/getToken.jsx'
import './Button.css';
const Button = ({selectedIcon}) => {
const [selected] = selectedIcon;
const [xappToken] = useState(getToken());
console.log(xappToken);
return(
<div className="buttonBlock">
<span className="btn">
<input className="btn-outline" type="button" value="Press Me" onClick={ () => getResponse(xappToken) }/>
</span>
</div>
);
}
export default Button
getToken.jsx
export default async function getToken(){
try {
const response = await axios.post('https://api.artsy.net/api/tokens/xapp_token', {
client_id: 'some-client-id',
client_secret: 'some-client-secret'
});
console.log('👉 Returned data:', response.data.token);
return response.data.token;
} catch (e) {
console.log(`😱 Axios request failed: ${e}`);
return "Error";
}
}
That's because getToken is a promise. You can do this:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import getResponse from '../Handler/getResponse.jsx'
import getToken from '../Handler/getToken.jsx'
import './Button.css';
const Button = ({selectedIcon}) => {
const [selected] = selectedIcon;
const [xappToken, setXappToken] = useState(null);
useEffect(() => {
getToken().then(token => setXappToken(token))
}, [])
console.log(xappToken)
return(
<div className="buttonBlock">
<span className="btn">
<input className="btn-outline" type="button" value="Press Me" onClick={ () => getResponse(xappToken) }/>
</span>
</div>
);
}
export default Button
if i remember correctly
since you're getting a promise your gonna have to await the response as well.
you have to json() your response and store it into something else
then console.log the new result
for example
const result = await response.json()
console.log(result)
Try this one:
import React, { useState } from 'react';
import axios from 'axios';
import getResponse from '../Handler/getResponse.jsx'
import getToken from '../Handler/getToken.jsx'
import './Button.css';
const Button = async ({selectedIcon}) => {
const [selected] = selectedIcon;
const [xappToken] = useState(await getToken());
console.log(xappToken);
return(
<div className="buttonBlock">
<span className="btn">
<input className="btn-outline" type="button" value="Press Me" onClick={ () => getResponse(xappToken) }/>
</span>
</div>
);
}
export default Button
I guess you also need to do an async await in the Button.jsx:
const Button = async ({ selectedIcon }) => {
const [selected] = selectedIcon;
const [xappToken] = useState(await getToken());
console.log(xappToken);
};
Since getToken is well, technically a promise. So you need to do an await before accessing the value of that.
Related
I am not able to retrieve content from API every time I reload my page it shows error, please see the attached image, I wanted to find the weather details using Weather API and right now I am using static latitude and longitude.
import React, { useState, useEffect } from "react";
import axios from "axios";
import { FaRegSun } from "react-icons/fa";
import "./stylesheets/stylesheets.css";
function WeatherApp1() {
const [weatherData2, setWeatherData2] = useState({});
const API_endpoint2 = `https://api.openweathermap.org/data/2.5/onecall?`;
const API_key = `2a63c27d8ba0b0d14c9e5d59f39ee1ba`;
useEffect(() => {
async function getSecondObject() {
const response = await axios.get(
`${API_endpoint2}lat=28.4360704&lon=77.021184&units=metric&appid=${API_key}`
);
setWeatherData2(response.data);
}
getSecondObject();
}, []);
return (
<div className="mainDiv">
<div className="heading">
<h1>
<FaRegSun /> Weather
</h1>
</div>
{weatherData2.current.temp}
</div>
);
}
export default WeatherApp1;
https://i.stack.imgur.com/oqr7i.jpg
The problem with your code is that you're trying to render {weatherData2.current.temp} before the data is returned from the weather API and that's why your weatherData2 will be undefined while rendering.
You can add a loading state for checking if the data is rendering or already rendered.
You can try below code:
import React, { useState, useEffect } from "react";
import axios from "axios";
import { FaRegSun } from "react-icons/fa";
import "./stylesheets/stylesheets.css";
function WeatherApp1() {
const [loading, setLoading] = useState(true) // Loading state
const [weatherData2, setWeatherData2] = useState({});
const API_endpoint2 = `https://api.openweathermap.org/data/2.5/onecall?`;
const API_key = `2a63c27d8ba0b0d14c9e5d59f39ee1ba`;
useEffect(() => {
async function getSecondObject() {
const response = await axios.get(
`${API_endpoint2}lat=28.4360704&lon=77.021184&units=metric&appid=${API_key}`
);
setWeatherData2(response.data);
setLoading(false) // Setting the loading state to false after data is set.
}
getSecondObject();
}, []);
return (
<div className="mainDiv">
<div className="heading">
<h1>
<FaRegSun /> Weather
</h1>
</div>
{/* Checking for loading state before rendering the data */}
{loading ? (
<p>Loading...</p>
) : (
weatherData2.current.temp
)}
</div>
);
}
export default WeatherApp1;
I need to display images from directus
import React, { useEffect, useState } from 'react'
import { fetchArticles } from './async/fetchArticels'
const FileUpload = () => {
const [articles, setArticles] = useState([])
useEffect(()=>{
fetchArticles().then(data => setArticles(data))
}, [])
return (
<div>
{articles.map(article =>
<div>
<h3>{article.title}</h3>
<img src={article.image} alt="img" />
</div>
)}
</div>
)
}
export default FileUpload
code
import axios from "axios"
export const fetchArticles = async () => {
const {data} = await axios.get('http://localhost:8055/items/articles')
console.log(data.data)
return data.data
}
from the directus I get this data
I read about the blob method, but I can't get it.
What should I do?
From the Directus Docs:
You can consistently access [your files/images] via the API using the following URL.
example.com/assets/<file-id>
example.com/assets/1ac73658-8b62-4dea-b6da-529fbc9d01a4
Reference: https://docs.directus.io/reference/files/#accessing-an-file
For You
As you're wishing to display images in the browser, you will likely want something like this.
<img src={"//example.com/assets/" + article.image}" alt={article.title} />
I'm creating React context but it returns a promise. In the file playlistcontext.js I've the following code:
import React, { useEffect } from 'react';
import YouTube from '../services/youtube';
const playlistsData = YouTube.getPlaylists();
// console.log(playlistsData);
const PlaylistsDataContext = React.createContext(playlistsData);
const PlaylistsDataProvider = (props) => {
const [playlists, setPlaylists] = React.useState(playlistsData);
useEffect(() =>{
const playlistsData = YouTube.getPlaylists();
console.log(playlistsData);
setPlaylists(playlistsData);
},[])
return <PlaylistsDataContext.Provider value={[playlists, setPlaylists]}>{props.children}</PlaylistsDataContext.Provider>;
}
export {PlaylistsDataContext, PlaylistsDataProvider};
In the file youtube.js, that I use it like a service, I'have the code below. In this function a console.log(result.data) return me the correct data.
import axios from 'axios';
import { YOUTUBE_API } from '../config/config';
function Youtube() {
const handleError = (resp) => {
let message = '';
switch (+resp.status) {
case 401:
message = resp.data.error;
break;
default:
message = 'general error';
}
return message;
}
const getPlaylists = async () => {
try {
const result = await axios.get(YOUTUBE_API + '');
return result.data;
} catch(e) {
return Promise.reject(handleError(e.response));
}
}
return {
getPlaylists
}
}
const ytMethod = Youtube();
export default ytMethod;
then, I have a containers "tutorialcontainer.js" in which I've wrapped a component:
import React, {useState} from 'react';
import { PlaylistsDataProvider } from '../containers/playlistscontext';
import Tutorials from '../components/tutorials';
const TutorialsContainer = (props) => {
return (
<PlaylistsDataProvider>
<Tutorials />
</PlaylistsDataProvider>
);
}
export default TutorialsContainer;
In the last file tutorials.js I have the component. In this file the console.log(playlist) returns me a promise.
import React, {useState, useEffect} from 'react';
import SectionBoxPlaylist from '../components/html_elements/card_playlist';
import Header from '../components/header';
import { PlaylistsDataContext } from '../containers/playlistscontext';
const Tutorials = (props) => {
const [playlists, setPlaylists] = React.useContext(PlaylistsDataContext);
return (
<div className="app-container">
<Header />
<div className="section section-one text-center">
<div className="section-content">
<div className="section-box-items">
{
Object.keys(playlists).map((item) => {
return <SectionBoxPlaylist key={item} id={item} info={playlists[item]} />
})
}
</div>
</div>
</div>
</div>
);
}
export default Tutorials;
Can you help and explain me why?
Thank you!
setPlaylists is called immediately after YouTube.getPlaylists().
useEffect(() => {
const playlistsData = YouTube.getPlaylists();
console.log(playlistsData); // playlistsData is not fetched
setPlaylists(playlistsData);
},[])
You should be able to use .then():
YouTube.getPlaylists().then(response => {
console.log(response);
setPlaylists(response);
});
You can also create async function inside useEffect():
useEffect(() => {
const getYTPlaylist = async () => {
const playlistsData = await YouTube.getPlaylists();
console.log(playlistsData);
setPlaylists(playlistsData);
}
getYTPlaylist();
},[])
I've set up my context and I have a function that runs once the form is submitted handleSubmit. When I submit the form, I want the results to be shown on a separate page dashboard. I'm using history.push().
My form is wrapped in the withRouter HOC.
When I submit the form, I receive "props.history is undefined"
I also have another function that is using a match.params and I'm getting undefined as well. So I'm assuming it has to do with React Router.
I considered that perhaps my Context file is the one that needs to be wrapped with the withRouter HOC, but the file has two exports.
My Context Provider
import React, { useState, useEffect, createContext } from 'react'
const AnimeContext = createContext()
const API = "https://api.jikan.moe/v3"
const AnimeProvider = (props) => {
const urls = [
`${API}/top/anime/1/airing`,
`${API}/top/anime/1/tv`,
`${API}/top/anime/1/upcoming`,
]
// State for Anime search form
const [dataItems, setDataItems] = useState([])
const [animeSearched, setAnimeSearched] = useState(false)
// Fetch searched Anime
async function handleSubmit(e) {
e.preventDefault()
const animeQuery = e.target.elements.anime.value
const response = await fetch(`${API}/search/anime?q=${animeQuery}&page=1`)
const animeData = await response.json()
setDataItems(animeData.results)
setAnimeSearched(!animeSearched)
props.history.push('/dashboard')
}
return (
<AnimeContext.Provider value={{
topTv,
setTopTv,
topAiring,
setTopAiring,
topUpcoming,
setTopUpcoming,
dataItems,
setDataItems,
animeSearched,
setAnimeSearched,
fetching,
anime,
fetchTopAnime,
fetchAnimeDetails,
handleSubmit
}}>
{props.children}
</AnimeContext.Provider>
)
}
export { AnimeProvider, AnimeContext }
My SearchForm component
import React, { useContext } from 'react';
import { withRouter } from 'react-router-dom'
import styled from 'styled-components'
import AnimeCard from './AnimeCard/AnimeCard';
import { AnimeContext } from '../store/AnimeContext'
const SearchForm = () => {
const { dataItems, animeSearched, handleSubmit } = useContext(AnimeContext)
return (
<div>
<Form onSubmit={handleSubmit}>
<Input
type="text"
name="anime"
placeholder="Enter title"
/>
<FormButton type='submit'>Search</FormButton>
</ Form>
{animeSearched
?
<AnimeCard
dataItems={dataItems}
/>
: null}
</div>
)
}
export default withRouter(SearchForm)
you can always use useHitory hook everywhere!
import { useHistory } from 'react-router'
...
const Page = function(props) {
let history = useHistory();
...
history.push('/')
...
}
In react-router, you would get history from props if any component is rendered as a child or Route or from an ancestor that is renderd form Route and it passed the Router props to it. However it is not receiving Router props, i suggest try this one
You can use Redirect from react-router-dom
import { Redirect } from "react-router-dom";
const [redirect, setRedirect] = useState(false);
Now set the vlue of redirect to true where ever you want
setRedirect(true);
like in your case
async function handleSubmit(e) {
e.preventDefault()
const animeQuery = e.target.elements.anime.value
const response = await fetch(`${API}/search/anime?q=${animeQuery}&page=1`)
const animeData = await response.json()
setDataItems(animeData.results)
setAnimeSearched(!animeSearched)
setRedirect(true);
}
Now you can use the following for the Redirection in return function like so
if(redirect) {
return <Redirect to="/dashboard" />
} else {
return (
<Your-Component />
)
I am using Easy Peasy State management for React. I would like to create multiple Axios call from one store location and import it in each page there where I need to show the correct data. I am trying to fetch a JSON placeholder data for example and use that inside a component to push it to the state using Hooks.
But I get the following error:
model.js:14 Uncaught (in promise) TypeError: actions.setTodos is not a function
at model.js:14
Can someone help me out? What am I doing wrong?
My code for the store (model.js):
import { thunk } from 'easy-peasy';
export default {
todos: [],
fetchTodos: thunk(async actions => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/todos?_limit=10'
);
const todos = res.json();
actions.setTodos(todos);
}),
};
My Page component Contact:
import React, { useState, useEffect } from 'react';
import { useStoreActions } from 'easy-peasy';
import ReactHtmlParser from 'react-html-parser';
import { API_URL } from 'constants/import';
// import axios from 'axios';
const Contact = () => {
const [contactPage, setContactPage] = useState([]);
const { page_title, page_content, page_featured_image } = contactPage;
const fetchTodos = useStoreActions(actions => actions.fetchTodos);
useEffect(() => {
fetchTodos();
}, []);
return (
<section className="contact">
<div className="page">
<div className="row">
<div className="col-xs-12">
<h3 className="section__title">{page_title}</h3>
{ReactHtmlParser(page_content)}
{page_featured_image && (
<img src={API_URL + page_featured_image.path} />
)}
</div>
</div>
</div>
</section>
);
};
export default Contact;
You need to use action.
import { action, thunk } from "easy-peasy";
export default {
fetchTodos: thunk(async (actions, payload) => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/todos?_limit=10"
);
const todos = res.json();
actions.setTodos(todos);
}),
todos: [],
setTodos: action((state, payload) => {
console.log("---->>> payload!")
state.todos = payload
}),
};
I usually use it like this, it works perfectly for me.