How to Use TanStack-Query to Write Cleaner React Code as a Junior Developer
Tags: react, beginners, programming, tutorial
Published: 2023-10-24 19:35:04

Showing data obtained by external sources is a core part of most frontend applications.

Most of the data comes from an API or a CMS. If the amount of data to be fetched is small, this can easily done with react-native hooks in combination with the fetch api. However, if the data flow between client and server grows more complicated, we are at risk of creating tons of unmaintainable spaghetti code.

To avoid this, we need a better tool for the job: React Query.

Here are the steps to get started with react query to improve your code:



###1.  Understand the difference between client state and server state

Client state lives in the browser, like form state, dark mode or whether a modal is opened or closed. Server state lives probably in some database and is served asynchronously.

Always use React Query for server state. Use native hooks like useState or useReducer for client state.


### 2. Install React-Query in your project

Follow the [installation instructions](https://tanstack.com/query/latest/docs/react/installation) and don't forget to set up the [query client provider](https://tanstack.com/query/latest/docs/react/quick-start) 


### 3. In your code, replace data fetching code and states with the useQuery hook

Instead of writing this:
```jsx
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch('https://rickandmortyapi.com/api/character');
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        const result = await response.json();
        setData(result.results);
      } catch (err) {
        setError(err);
      } finally {
        setLoading(false);
      }
    }

    fetchData();
  }, []);

```
write this:
```jsx
function fetchRickAndMortyCharacters() {
  return fetch('https://rickandmortyapi.com/api/character')
    .then(response => {
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      return response.json();
    })
    .then(data => data.results);
}

  const { data, isLoading, isError, error } = useQuery(['rickAndMortyCharacters'], fetchRickAndMortyCharacters);

```

The data you need to render will be in the destructured `data`. Here is an example of how you can render the result:

```jsx
  if (isLoading) return <p>Loading...</p>;
  if (isError) return <p>Error: {error.message}</p>;
  if (!data) return <p>No data available</p>;

  return (
    <ul>
      {data.map(character => (
        <li key={character.id}>{character.name}</li>
      ))}
    </ul>
  );
```
### 4. Convert the useQuery hook into a custom hook
For better reusability, abstract this into a custom hook:

```jsx
export function useRickAndMortyCharacters() {
  return useQuery(['rickAndMortyCharacters'], fetchRickAndMortyCharacters);
}

```

now, from any component, you can just call the custom hook like so:

```jsx
const { data, isLoading, isError, error } = useRickAndMortyCharacters();

```
That's it! If you want to go any further, read the docs and play around with different [query options](https://tanstack.com/query/latest/docs/react/reference/useQuery) or with [mutations](https://tanstack.com/query/latest/docs/react/guides/mutations).

Thanks for reading!