3

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:

  • an input function called SymbolInput() that sends user requested data to my database.
  • a table function, PriceUpdate() that loads data from my database via useEffect.
  • createContext as the transmitter to reload the table via useEffect dependency array if data has been sent to my database and cause a re-render based on state change.

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>
    );
}
andres
  • 1,558
  • 7
  • 24
  • 62
  • Can you show an example of where `PriceUpdate` is used? Specifically, is `PriceUpdate` nested inside a `TableRefreshContext.Provider` somewhere? – maazadeeb Feb 26 '21 at 03:37
  • Instead of reloadTable use data in your useEffect function param – Yadab Feb 26 '21 at 03:43
  • Hi maazadeeb, it is not nested with TableRefreshContext.Provider, let me test that out. Please see my updated post. – andres Feb 26 '21 at 04:02
  • Yadab, I just tried doing that, the tables seems to update but my useEffect seems to be stuck in a repeated loop that continuously making requests to my server now :) – andres Feb 26 '21 at 04:02

4 Answers4

2

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.

kunquan
  • 1,127
  • 1
  • 10
  • 24
0

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);
}, [])
Rahul Shah
  • 1,433
  • 5
  • 7
  • Thank you for the recommendations, I'm still however not able to render the new data. The closest I was able was adding `data` to the dependency array to the useEffect, but that managed to get me stuck in an endless loop requests to my server. – andres Feb 26 '21 at 05:46
0

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.

Mohammad Zubair
  • 413
  • 4
  • 12
  • Nope. He hasn't set state in a way that changes the dependency array. It would only be an infinite loop if it changed the context in some way. – Rahul Shah Feb 26 '21 at 05:25
0

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.

maazadeeb
  • 5,922
  • 2
  • 27
  • 40
  • Thank you, I think im closer to achieving the re-render, but still the table does not seem to be re-rendering – andres Feb 26 '21 at 18:13
  • @woof can you create a codesandbox to reproduce your problem? Not able to understand the problem with the given details. – maazadeeb Feb 26 '21 at 19:14