Reputation: 62
I am writing a straightforward react app with a very basic api (git hub repo: https://github.com/mrarthurwhite/use_effect_react_hooks_demo). Following is the functional component which is a demo component meant to illustrate a fetch (with axios
), using the useEffect
hook, followed by just displaying the data.
import './App.css';
import React, { useEffect, useState } from 'react';
import axios from 'axios';
function GetWordsWAxiosNLoading() {
const [words, setWords] = useState([]);
let isLoading = false;
let [isLoadings, setIsLoadings] = useState(false); // initially using state variable
console.log("isLoading prefetch " + isLoading);
async function fetchData(){
//setIsLoading(true);
isLoading = true;
console.log("isLoading fetching " + isLoading);
let url = 'http://localhost:1111/wordlist';
const result= await axios(url);
setWords(result.data);
//setIsLoading(false);
isLoading = false;
console.log("isLoading resetting " + isLoading);
};
useEffect(() => {fetchData()}, [] );
console.log("isLoading postfetch " + isLoading);
return (
<>
{ isLoading? (<div>Loading . . . </div>) : ( {words.map(w=> <div>{w.word}</div>)} ) }
</>
);
}
export default GetWordsWAxiosNLoading;
The error I am getting is :
./src/GetWordsWAxiosNLoading.js
SyntaxError: use_effect_react_hooks_demo/use_effect_initial_demo/src/GetWordsWAxiosNLoading.js: Unexpected token (27:59)
25 | return (
26 | <>
> 27 | { isLoading? (<div>Loading . . . </div>) : ( {words.map(w=> <div>{w.word}</div>)} ) }
| ^
28 | </>
29 | );
30 | }
At line 27 above it is giving both a Line 27:60: Parsing error: Unexpected token
& a SyntaxError
.
I have working variants of the above :
fetch
instead of axios
httpclient (https://github.com/mrarthurwhite/use_effect_react_hooks_demo/blob/master/use_effect_initial_demo/src/App.js), & it works fine but initially it was giving me similar errors (words was undefined & it could not find .map) indicating that the errors returned are stock & perhaps not very descriptive nor accurate.axios
but without a loading variable ( https://github.com/mrarthurwhite/use_effect_react_hooks_demo/blob/master/use_effect_initial_demo/src/GetWordsWAxios.js) & it works fineThe issues are:
isLoading
variable is undefined
(I was initially using isLoadings
a variable stored in the state object but decided to simplify it).Any ideas as to what could be going on?
Upvotes: 1
Views: 147
Reputation: 1610
isLoading should be state of component
function GetWordsWAxiosNLoading() {
const [words, setWords] = useState([]);
let [isLoading, setIsLoading] = useState(false);
async function fetchData() {
setIsLoading(true);
const result = await axios("http://localhost:1111/wordlist");
setWords(result.data);
setIsLoading(false);
}
useEffect(() => {
fetchData();
}, []);
return (
<>
{isLoading ? (
<div>Loading . . . </div>
) : (
words.map((w) => <div>{w.word}</div>)
)}
</>
);
}
export default GetWordsWAxiosNLoading;
Upvotes: 0
Reputation: 371168
You need to be careful and cognizant of when you're in a section where you're using JSX syntax, and when you're in a section of plain JavaScript expressions (which may include JSX elements).
When writing JSX, you can interpolate JavaScript expressions by enclosing them in {}
s, eg:
<div className={someClassName}
or
<span>{someText}</span>
That's the only time you should be using {}
as delimiters for interpolation. Here:
<>
{ isLoading? (<div>Loading . . . </div>) : ( {words.map(w=> <div>{w.word}</div>)} ) }
</>
The first {
is needed to go from the JSX fragment to a standard JS expression, but in the second part of the conditional, you're not starting from a JSX context, so you shouldn't have {
. This:
: ( {words.map
should be
: words.map
You should also remove the isLoading
plain variable, and use the isLoadings
stateful variable instead. To change state in React, call the state setter - you should almost never be reassigning the value of a plain variable.
Cleaning up your code a bit, try:
function GetWordsWAxiosNLoading() {
const [words, setWords] = useState([]);
const [isLoading, setIsLoading] = useState(true);
async function fetchData() {
const url = 'http://localhost:1111/wordlist';
const result = await axios(url);
setWords(result.data);
setIsLoading(false);
}
useEffect(fetchData, []);
return isLoading
? <div>Loading . . . </div>
: words.map(w => <div>{w.word}</div>);
}
If the words
array returned by the API always contains at least one item, you could also remove the isLoading
state entirely and just check words.length
instead. If 0, it's still loading.
Upvotes: 2