1

I have a React component that fetches some data from IndexedDB that is an asynchronous task it uses the id from the url passed in by the useParams hook, let say id = 1. When I click on the link in the example the id changes to 2 but at this point nothing happens the component does not rerender.

What do I need to do to make it work? I just don't understand why it does not work right now. Can someone enlighten me?

import React, {useState} from 'react';
import { Link, useParams } from "react-router-dom";
import { useAsync } from 'react-async';

export default function (props) {
  let { id } = useParams();

  const { data, error, isLoading } = useAsync({
    promiseFn: loadData,
    id: parseInt(id)
  });

  if (isLoading) return "Loading...";
  if (error) return `Something went wrong: ${error.message}`;
  if (data)
    return (
      <>
        <h1>{data.name}</h1>
        <Link to={'/2'}>other id</Link>
      </>
     );
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Smek
  • 1,158
  • 11
  • 33

2 Answers2

2

Async functions should be called inside useEffect hook. The useEffect will always be called when id changes.

import React, { useState } from "react";
import { Link, useParams } from "react-router-dom";
import { useAsync } from "react-async";

export default function(props) {
  let { id } = useParams();

  const [error, setError] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [data, setData] = useState(null);

  useEffect(() => {
    const { data, error, isLoading } = useAsync({
      promiseFn: loadData,
      id: parseInt(id)
    });
    setIsLoading(isLoading);
    setError(error);
    setData(data)
  }, [id]);

  if (isLoading) return "Loading...";
  if (error) return `Something went wrong: ${error.message}`;
  if (data)
    return (
      <>
        <h1>{data.name}</h1>
        <Link to={"/2"}>other id</Link>
      </>
    );
}
Jagrati
  • 11,474
  • 9
  • 35
  • 56
  • I tried this code but the data, error, and isLoading variables are not accessible in the if statements and below. Do I need to set some state in the useEffect function with useState? – Smek Apr 27 '20 at 11:09
  • 1
    Yes you won't be able to access it outside the useEffect , since its a `const` blocked scope. You would need to store the values in state using `useState` – Jagrati Apr 27 '20 at 11:30
  • 1
    Jagrati thank you. Your answer did not entirely solve my problem but you pointed me in the right direction. The issue has something to do with useAsync from the react-async library. It looks like the useAsync function already uses the useEffect function. When I call my loadData function from the useEffect function everything works just fine. – Smek Apr 28 '20 at 07:33
1

When using the useAsync hook from the react-async library you can use the watch or the watchFn option the watch for changes. So changing the following line:

const {data, error, isLoading} = useAsync({ promiseFn: loadData, id: parseInt(id)});

to:

const {data, error, isLoading} = useAsync({ promiseFn: loadData, id: parseInt(id), watch: id});

did the trick.

Smek
  • 1,158
  • 11
  • 33