I am trying to create a hook in my application made on Create React App, but when updating the constant that contains the information, the component that shows the list on the screen is not rendered again, but the list is updated, since the hook returns it updated in console (it is worth mentioning that when loading the component for the first time, it is rendered correctly, but it is not updated when the information changes).
Sales List
import React, { use, useState, useEffect } from 'react';
import { Table } from 'antd';
import UpdateList from '../hooks/updateList';
const SalesList = () => {
const { list, loading, error, updateList } = UpdateList();
useEffect(() => {
updateList();
}, []); /* If I add updateList within the [], it works, but it enters an infinite loop */
useEffect(() => {
console.log('List updated in the component:', list);
}, [list]);
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Price',
dataIndex: 'price',
key: 'price',
},
{
title: 'Quantity',
dataIndex: 'quantity',
key: 'quantity',
},
{
title: 'Amount Received',
dataIndex: 'amountReceived',
key: 'amountReceived',
},
];
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <Table dataSource={list} columns={columns} rowKey="ID" />;
};
export default SalesList;
UpdateList
import { useState, useEffect } from 'react';
import useFetchData from '../services/api/showData';
const UpdateList = () => {
const { data, loading, error, fetchData } = useFetchData();
const [list, setList] = useState([]);
const updateList = async () => {
try {
const newList = await fetchData();
setList([...newList]);
console.log('New list obtained:', newList);
} catch (error) {
console.error('An error occurred while updating your data', error);
}
};
useEffect(() => {
updateList();
}, [fetchData]);
return { list, loading, error, updateList };
};
export default UpdateList;
ShowData
import { useState, useEffect, useCallback } from "react";
import axios from 'axios';
const useFetchData = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
setLoading(true);
try {
const response = await axios('http://localhost/REACT/my-app/src/backend/php/api/mostrarDatos.php');
if (!response.data.ok) {
return console.error('An error occurred, please restart. If the issue persists, contact the administrator.');
}
setData(response.data.respuesta);
return response.data.respuesta;
} catch (error) {
setError(error instanceof Error ? error : new Error("An unknown error occurred"));
console.error("Error fetching data:", error);
return [];
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
return { data, error, fetchData };
};
export default useFetchData;
I need that when updating the constant lista, the component that creates the table is updated, the hook is working but it is not re-rendering the data.
I am trying to create a hook in my application made on Create React App, but when updating the constant that contains the information, the component that shows the list on the screen is not rendered again, but the list is updated, since the hook returns it updated in console (it is worth mentioning that when loading the component for the first time, it is rendered correctly, but it is not updated when the information changes).
Sales List
import React, { use, useState, useEffect } from 'react';
import { Table } from 'antd';
import UpdateList from '../hooks/updateList';
const SalesList = () => {
const { list, loading, error, updateList } = UpdateList();
useEffect(() => {
updateList();
}, []); /* If I add updateList within the [], it works, but it enters an infinite loop */
useEffect(() => {
console.log('List updated in the component:', list);
}, [list]);
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
},
{
title: 'Price',
dataIndex: 'price',
key: 'price',
},
{
title: 'Quantity',
dataIndex: 'quantity',
key: 'quantity',
},
{
title: 'Amount Received',
dataIndex: 'amountReceived',
key: 'amountReceived',
},
];
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <Table dataSource={list} columns={columns} rowKey="ID" />;
};
export default SalesList;
UpdateList
import { useState, useEffect } from 'react';
import useFetchData from '../services/api/showData';
const UpdateList = () => {
const { data, loading, error, fetchData } = useFetchData();
const [list, setList] = useState([]);
const updateList = async () => {
try {
const newList = await fetchData();
setList([...newList]);
console.log('New list obtained:', newList);
} catch (error) {
console.error('An error occurred while updating your data', error);
}
};
useEffect(() => {
updateList();
}, [fetchData]);
return { list, loading, error, updateList };
};
export default UpdateList;
ShowData
import { useState, useEffect, useCallback } from "react";
import axios from 'axios';
const useFetchData = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchData = useCallback(async () => {
setLoading(true);
try {
const response = await axios('http://localhost/REACT/my-app/src/backend/php/api/mostrarDatos.php');
if (!response.data.ok) {
return console.error('An error occurred, please restart. If the issue persists, contact the administrator.');
}
setData(response.data.respuesta);
return response.data.respuesta;
} catch (error) {
setError(error instanceof Error ? error : new Error("An unknown error occurred"));
console.error("Error fetching data:", error);
return [];
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
return { data, error, fetchData };
};
export default useFetchData;
I need that when updating the constant lista, the component that creates the table is updated, the hook is working but it is not re-rendering the data.
Custom hook's function name should always start with 'use' as per react best practices and docs. Your 'useFetchData' follows this condition and hence can be considered a hook. But 'UpdateList' looks more like a react component than a hook. You can change it to 'useUpdateList' to make it more coherent and clear.
Also you need not return the function that is used to make the API call like that since you are returning the list that is being fetched using the API.
Also you are setting data in your useFetchData but you are not using it anywhere. You can try the following:
In your useFetchData,
const useFetchData = () => {
//......
return {data, loading, error}
}
In your SalesList component, you can call your useFetchData directly.
const SalesList = () => {
const { list, loading, error } = useFetchData();
//.......
}
UpdateList
is supposed to be a custom React hook then it should be named like one, i.e. named using a"use-"
prefix, e.g.useUpdateList
. Why doesUpdateList
effectively duplicate the fetched data state and effect?useFetchData
also doesn't return a definedloading
property value. WhenupdateList/fetchData
is/are called does any new data get returned? Have you checked/verified that the AntDTable
component rerenders when passed a differentdataSource
prop value? – Drew Reese Commented Feb 1 at 0:59