I use to react and nearby. I need to export a component, but I don't have the right to put it in a function
function Index(){
}
export default Index
You must receive a request, but you can only write to a variable if the function is asynchronous.
I had to create a wrapper
async function asy(){
const data = await fetchData()
function Index(){
}
export default Index
}
asy().then(r => r);
Now I can't export the component.
I found a different solution, but it doesn't work either.
function Index(){
return async function asy(){
//async function.
const data = await fetchData()
return <React.Fragment/>
}
}
export default Index
I Don't think I fully understand your question but here is what I understood,
You want to return a component after making an async request to retrieve data.
I would go for something like this:
function Index() {
const [data, setData] = React.useState(null);
retrieveData = async () => {
// Retrieve your data
setData(retrievedData);
}
useEffect(() => {
retrieveData();
}, [])
if (data != null) {
return <YourComponent />
} else {
return null
}
}
This code will call the retrieveData function each time this component is mounted
Related
I'm working on a react project where I have created an API and that I want to use for my react project, I'm dealing with react hooks and not able to call API correctly. I have tried couple of things, but I keep getting one or other kind of error.
Latest method I have tried is giving me this error
Line 8:20: React Hook "useFetch" is called in function "filterList" which is neither a React function component or a custom React Hook function
Code for filterList.js look like this
/* to filter the products based on the categories */
import useFetch from './apiService'
export default function filterList(arr, method, courses) {
const URL = "http://localhost:8000/api/getCourses";
const result = useFetch(URL, {});
courses = result;
console.log(courses, 'Inside filterList')
if(method == null) return courses;
else {
return courses.filter(course => {
const categoryArray = course.category.split(" ");
if(arr.length > 0) {
if(categoryArray.some(r => arr.indexOf(r) >= 0)) {
return course;
}
}
else {
return courses;
}
return courses;
})
}
}
and code for apiService.js where I have created useFetch function look like this
import { useEffect, useState } from 'react';
// to fetch the data from api
const useFetch = (url, defaultData) => {
const [data, updateData] = useState(defaultData);
useEffect(() => {
async function fetchData() {
const response = await fetch(url);
const json = await response.json();
updateData(json);
}
fetchData();
}, [url]);
return data;
};
export default useFetch;
Please let me know what is the thing that I'm doing wrong and what should be correct method to do this.
I am trying to use a react hook like useMemo or useEffect inside my functional component. The API call is async, and I think that may be what's causing the error.
Service file:
export const getData = (): wretch =>
fetch('/d/get_data')
.get()
.json();
Data formatting logic file:
import {getData} from './services';
export const formatData = (onClick, onSort) => {
// logic here - omitted
const formattedData = [];
return getData().then(res => {
res.forEach(
// more data formatting logic
)
return {formattedData: formattedData, originalData: res};
})};
Rendering file:
import {formatData} from './formatData';
const MyTable = () => {
useEffect(() => formatData({onClick: handleClick, onSort: handleSort}).then(res => setData(res)), []);
Error message:
You're correct about the part where you cant have async code in your useEffect. A workaroud for that is similar to what you're doing.
useEffect(() => {
async function myfunc(){
// Do async work
const response = await apiCall();
setData(response);
}
myFunc();
},[])
This might not answer your question, but it is a common pattern you might find useful :)
Please try this one.
const MyTable = () => {
useEffect(async () => {
const data = await formatData({onClick: handleClick, onSort: handleSort});
setData(data);
},
[]);
}
Beginner here.
Trying to fetch some data from a server and display it in my react component once its fetched.
However, I am having trouble integrating the async function into my react component.
import React, { useState } from "react";
import { request } from "graphql-request";
async function fetchData() {
const endpoint = "https://localhost:3090/graphql"
const query = `
query getItems($id: ID) {
item(id: $id) {
title
}
}
`;
const variables = {
id: "123123123"
};
const data = await request(endpoint, query, variables);
// console.log(JSON.stringify(data, undefined, 2));
return data;
}
const TestingGraphQL = () => {
const data = fetchData().catch((error) => console.error(error));
return (
<div>
{data.item.title}
</div>
);
};
export default TestingGraphQL;
I'd like to simply show a spinner or something while waiting, but I tried this & it seems because a promise is returned I cannot do this.
Here you would need to use the useEffect hook to call the API.
The data returned from the API, I am storing here in a state, as well as a loading state to indicate when the call is being made.
Follow along the comments added in between the code below -
CODE
import React, { useState, useEffect } from "react"; // importing useEffect here
import Layout from "#layouts/default";
import ContentContainer from "#components/ContentContainer";
import { request } from "graphql-request";
async function fetchData() {
const endpoint = "https://localhost:3090/graphql"
const query = `
query getItems($id: ID) {
item(id: $id) {
title
}
}
`;
const variables = {
id: "123123123"
};
const data = await request(endpoint, query, variables);
// console.log(JSON.stringify(data, undefined, 2));
return data;
}
const TestingGraphQL = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
// useEffect with an empty dependency array works the same way as componentDidMount
useEffect(async () => {
try {
// set loading to true before calling API
setLoading(true);
const data = await fetchData();
setData(data);
// switch loading to false after fetch is complete
setLoading(false);
} catch (error) {
// add error handling here
setLoading(false);
console.log(error);
}
}, []);
// return a Spinner when loading is true
if(loading) return (
<span>Loading</span>
);
// data will be null when fetch call fails
if (!data) return (
<span>Data not available</span>
);
// when data is available, title is shown
return (
<Layout>
{data.item.title}
</Layout>
);
};
since fetchData() returns a promise you need to handle it in TestingGraphQL. I recommend onComponentMount do your data call. Setting the data retrieved into the state var, for react to keep track of and re-rendering when your data call is finished.
I added a loading state var. If loading is true, then it shows 'loading' otherwise it shows the data. You can go about changing those to components later to suit your needs.
See the example below, switched from hooks to a class, but you should be able to make it work! :)
class TestingGraphQL extends Component {
constructor() {
super();
this.state = { data: {}, loading: true};
}
//when the component is added to the screen. fetch data
componentDidMount() {
fetchData()
.then(json => { this.setState({ data: json, loading: false }) })
.catch(error => console.error(error));
}
render() {
return (
{this.state.loading ? <div>Loading Spinner here</div> : <div>{this.state.data.item.title}</div>}
);
}
};
I want to make a function in react that get called on every component that need the data to be fetched. I tried this by the way but it returns a Promise type and not the data I need. Instead if I do console.log(res.data.user) it brings the data. Why I cannot return and have it ready to be implemented in every component I need?
import React, { Component } from 'react';
import { useQuery } from "#apollo/react-hooks";
import query from './queries/CurrentUser';
import receive_client from "./Client";
const CurrentUserQuery = async function () {
const client = receive_client()
const result = await client.query({ query: query }).then((res) => {
return res.data.user
})
}
export default CurrentUserQuery;
and here I call it
import React, { Component } from 'react';
import CurrentUser from '../../CurrentUserQuery'
class Home extends Component {
render(){
console.log(CurrentUser())
return(
<div></div>
)
}
}
It looks like you aren't returning from your CurrentUserQuery function,
const CurrentUserQuery = async function () {
const client = receive_client()
const result = await client.query({ query: query }).then((res) => {
return res.data.user
})
if(result){
return result
}
}
The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
In CurrentUserQuery function you should use either await or then().
const CurrentUserQuery = async function () {
try{
const client = receive_client()
const response = await client.query({ query: query })
return {success: true, user:response.data.user}
}catch (err){
return {success: false}
}
}
export default CurrentUserQuery;
/* CurrentUser function return a promise. To get the resolved
value you have to pass a callback to 'then()'
which will be executed the callback once the promise is resolved.
*/
class Home extends Component {
componentDidMount(){
CurrentUser().then(({user, success}) => {
if(success)this.setState({user})
})
}
//.... Rest Of Code .....
}
I do have a SplashContainer with a async componentDidMount
export class SplashContainer extends Component {
async componentDidMount() {
let token = await AsyncStorage.getItem('#XXX:token')
if (token !== null) {
await this.props.setTokenAvalability(true)
await this.props.getUserDetails()
}
await this.props.navToNextScreen()
}
render() {
return <Splash />
}
}
function mapDispatchToProps(dispatch) {
return {
navToNextScreen: () => dispatch(navToNextScreen(...)),
setTokenAvalability: (status) => dispatch(setTokenAvalability(status)),
getUserDetails: () => dispatch(getUserDetails()),
}
}
export default connect(null, mapDispatchToProps)(SplashContainer);
I do have two questions here.
1. I wanted to test setTokenAvalability and getUserDetails is been dispatched or not. I do know how to test if there is no async/await, like below.
it('test SplashContainer', () => {
const store = mockStore({});
const props = {
dispatch: store.dispatch
}
const tree = renderer.create(
<SplashContainer {...props}/>
).toJSON();
const expectedAction = [
...
]
expect(store.getActions()).toEqual(expectedAction);
});
2. How to stub value for AsyncStorage.getItem()
Thanks,
Well, componentDidMount is not an async function, the only thing you can do here I think is to use the componentDidUpdate method which will give you an update of your component.
Reading the this.props.navToNextScreen() function, I think you misunderstand how redux works here.
You probably don't need to wait for the navToNextScreen function, it should just send a global event and your main component should listen to a change in your store to show / hide your Splash screen