Reputation: 1796
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:
SymbolInput()
that sends user requested data to my database.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>
);
}
Upvotes: 3
Views: 2529
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
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
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
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