I'm fetching data from a server. And which component I'm going to show depends on the result of the fetching.
const response = fetch(url)
.then((result) => result.json())
.then((data) => data)
.catch((e) => {
console.log(e);
});
return {response.id ? <span>success!</span> : <span>fail</span>};
But this is TSX, not JSX. And the problem is that I don't understand how to make it work with TypeScript. Terminal tells me that React failed to compile the line with a ternary operator. Could you please help me to fix that?
CodePudding user response:
You should create a state for the response since you want the component to re-render with the data once the data is fetched.
const [data, setData] = useState({});
then if you wanna fetch the data once, optimally wrap it around useEffect:
useEffect(() => {
fetch("someUrl")
.then((result) => result.json())
.then((data) => {
if (data) setData(data);
})
.catch((e) => {
console.log(e);
});
}, []);
And then simply check if data is empty or not. Once it fetches, it will update the state to the fetched data which will re-render the component and display it.
return <>{(data && data.id) ? <span>success!</span> : <span>fail</span>}</>
CodePudding user response:
Try to remove {}
:
return response.id ? <span>success!</span> : <span>fail</span>;
Try to replace {}
with ()
:
return (response.id ? <span>success!</span> : <span>fail</span>);
Try to use React Fragment:
return <>{response.id ? <span>success!</span> : <span>fail</span>}</>;
You made a mistake when working with Promise: You can not use raw Promise in React. You should use one of the ways:
Create state with data value, loading flag, error
import { FC, useEffect, useState } from "react";
export const LoadData1: FC<Props> = ({ fetchData }) => {
const [response, setResponse] = useState<MyResponse>();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<any>();
useEffect(() => {
setLoading(true);
setError(undefined);
setResponse(undefined);
fetchData().then(
(data) => {
setLoading(false);
setResponse(data);
},
(e) => {
setLoading(false);
setError(e);
}
);
}, [fetchData]);
if (loading) {
return <>Loading in progress...</>;
}
if (error || !response) {
return <div>An error has occurred: "{error}"</div>;
} else {
return response.id ? (
<span>
success! Data #{response.id} and '{response.text}' has been fetched.
</span>
) : (
<span>fail</span>
);
}
};
Use ready-made React hooks
You can use react-use/useAsync.
import { FC } from "react";
import { useAsync } from "react-use";
export const LoadData2: FC<Props> = ({ fetchData }) => {
const { value, loading, error } = useAsync(fetchData, [fetchData]);
if (loading) {
return <>Loading in progress...</>;
}
if (error || !value) {
return <div>An error has occurred: "{error}"</div>;
} else {
return value.id ? (
<span>
success! Data #{value.id} and '{value.text}' has been fetched.
</span>
) : (
<span>fail</span>
);
}
};
Codesandbox was created to show this.