Home > Software engineering >  How to use ternary operator for rendering components in TSX?
How to use ternary operator for rendering components in TSX?

Time:11-27

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.

  • Related