yung peso
yung peso

Reputation: 1796

How to fix my React Context to render useEffect and reload table data

I have an input form that selects data to be rendered inside my tables. The data only appears after a forced page reload. I would like for the data to re-render with the expected data entered by the user after each submit in my input.

To do so I have:

The problem: I am not getting any errors and I know I'm doing something wrong, I cannot wrap my head around context API for my specific use-case. Hence I would greatly appreciate some clarification for myself to understand useContext and its provider.

Here is my code:

Below I initiate my createContext:

import { createContext } from 'react';

export const TableRefreshContext = createContext();
export default TableRefreshContext;

Then import the context to my file which contains my input form. Here I use state as a trigger/key to re-render my table. If data is sent to my db, then the state key increments by one, to hopefully fire off the useEffect dependency array in my table function.

import TableRefreshContext from '../../../context/TableRefresh';

export default function SymbolInput()
{
  const { control, handleSubmit } = useForm();
  const [refreshKey, SetRefreshKey] = useState([0])

  const onSubmit = (data, e) =>
  {  

    axiosInstance
      .patch(URL, {
        stock_list: data.stock_list.map(list=>list.symbol),
      })
      .then((res) =>
      {
        SetRefreshKey(refreshKey + 1);
      });
  };

  return (
    <TableRefreshContext.Provider value={refreshKey}>
            <form> 
            </form> 
    </TableRefreshContext.Provider>
    );
}

Here is the table function I speak of, where I have a useEffect to pull data from my db, along with it's dependency array.

export function PriceUpdate()
{
    const [data, setData] = useState([]);
    const reloadTable = useContext(TableRefreshContext)
    useEffect(() =>
    {
        const fetchData = async () =>
        {
            const response = await axiosInstance.get(URL)
            const result = response.data;
            setData(result);
        };

        fetchData();
    }, [reloadTable]);

    return (
        <>
            <div>
            <TableRefreshContext.Provider value={reloadTable}>
                <PriceUpdates data={data[0]} />
                <PriceRanges data={data[0]} />
                <ReturnRates data={data[1]} />
                <QuickFacts data={data[2]} />
                <Recommendations data={data[4]} />
                <AdvancedStats data={data[3]} />
            </TableRefreshContext.Provider>

How can I link up my input and table functions together to allow for my page to render new data without having to reload my entire page?

EDIT: Here is how I use PriceUpdate component, it's one of the children of my layout component:


    const reloadTable = useContext(TableRefreshContext)

    return (
            <TableRefreshContext.Provider value={reloadTable}>
                <PriceUpdate />
            </TableRefreshContext.Provider>
    );
}

Upvotes: 3

Views: 2529

Answers (4)

kunquan
kunquan

Reputation: 1267

From the current code that you have given, I don't think there is anything wrong with it, except for the refreshKey that should be a number instead of an array. I created a CodeSandbox project that is almost identical to your app and found nothing wrong with it (note that this way of using Context is not recommended as it should be in a higher hierarchy, as mentioned in a previous post).

If your code still not work, then try to create a CodeSandbox project that can reproduce your problem.

Upvotes: 2

maazadeeb
maazadeeb

Reputation: 6112

From the react docs for useContext

Accepts a context object (the value returned from React.createContext) and returns the current context value for that context. The current context value is determined by the value prop of the nearest <MyContext.Provider> above the calling component in the tree

...where, MyContext is analogous to your TableRefreshContext. So you need to make sure PriceUpdate has TableRefreshContext.Provider somewhere higher in the hierarchy. You have mentioned in a comment that it is not nested. I don't think it's possible for it to receive the changed context value without the nesting.

Upvotes: 0

Mohammad Zubair
Mohammad Zubair

Reputation: 413

It will go in a loop as you have set the state inside the useEffect().It's ok to use setState in useEffect() you just need to have attention as described already to not create a loop can you check the error in console.

Upvotes: 0

Rahul Shah
Rahul Shah

Reputation: 2043

Just off the cuff, one thing I see wrong with your code is that in the useState for refreshKey, you've initialized an array containing 0 i.e. [0] rather than the number 0. So your setRefreshKey isn't working as expected. This should solve your problem.

Another recommendation, remove your fetchData function from the useEffect. It's defining the function again on each render. Instead define it outside the useEffect using a useCallback:

const fetchData = useCallback(async () => {
  const response = await axiosInstance.get(URL)
  const result = response.data;
  setData(result);
}, [])

Upvotes: 0

Related Questions