简体   繁体   中英

Why my component doesn't rerender when context is updated?

I wanna render a table after fetching data from an API, I use the Context API and a custom hook to update the context. I know that my hook is working because of the second useEffect that logs the data. I'm aware that state updates in React are asynchronous, but I thought a change in the context would trigger a rerender.

import React, { useEffect, useContext } from "react";

import { titleCase } from "title-case";
import dataContext from "../../context/dataContext";

const fetchUsers = async (url:string) => {
  const response = await fetch(url);
  return response.json();
};


const Table = () => {
  const {data, setData } = useContext(dataContext);

  useEffect(() => {
    fetchUsers(`https://randomuser.me/api/?results=50`).then(
      (res) => {setData([...data, res.results]) ;

      }
    )
    
  }, [])

  useEffect(() => {
    console.log(data)
  }, [data])
    
  return (
    <table>
      <thead>
        <tr>
          <th>
            Name
          </th>
          <th>
            Gender
          </th>
          <th>
            Birth
          </th>
          <th>
            Actions
          </th>
        </tr>
      </thead>
      <tbody>
        {data.length >0 && data.map((user: Record<string, any>, index: number) => {
            const dob = new Date(user.dob.date);

            return (
              <tr>
                <td>
                  {`${titleCase(user.name.first)} ${titleCase(user.name.last)}`}
                </td>
                <td>
                  {titleCase(user.gender)}
                </td>
                <td>
                  {dob.toLocaleDateString()}
                </td>
                <td>
                  <button>View</button>
                </td>
              </tr>
            );
          })}
       
      </tbody>
    </table>
  );
};

export default Table;

There are multiple issues with the code that you have posted.

  1. you need to de-structure res.results inside setData. If you don't do it, the array of user will be stored as a single object instead of storing all the multiple user objects. setData([...data, ...res.results)
  2. You should provide a unique key for each child inside a list. Know more about it here . You can use the login.uuid field for each user as the key. <tr key={user.login.uuid}>
  3. You need to provide data as a dependency for the useEffect hook.
  4. Finally, it is better if you make calls to random user API using a set interval, if not the useEffect hook gets executed continuously.

I made a simple demo, which follows the above points. In the demo, I'm not using context. I'm fetching 2 new users every 10 seconds and then updating a table with their emails. link for demo .

I know this is a late post but I have spent some time looking into this and thought this might help you. Hopefully you have solved your issue by now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM