React-Query: callback after setQueryData - javascript

In a form, upon receiving a response from server, I update the cache using setQueryData. However, after the cache update, I want to trigger the form input field to be focused again.
Details:
In my React app, I am using Recoil.js to manage the state. React-Query is used to fetch & cache the data. I normalise the data & store in Recoil state, to which the React components subscribe for update.
While React-Query's setQueryData is a synchronous function, however, the app refresh because of new data is not (& any call after the setQueryData is not actioned).
How can I trigger the form input focus after the refresh of cache?

you can just call the focus function right after you call setQueryData, as it's synchronous:
setQueryData(key, newData)
focusField() //some function that focuses the field
alternatively, you can spawn a useEffect that always does something when data updates:
const { data } = useQuery(...)
useEffect(() => {
focusField()
}, [data])

Related

How do I set ANT DESIGN INITIAL VALUE form from API response

How do I set initialValues on ant design?
I want response.data(as shown on console.log) to be my initialValues on my Form.
HERE IS MY OLD CODE
The Form component does not re-render when the initial values change. So when your component mounts there is no response from the API yet and therefore the form is initialized with empty values (before API response is returned).
The sequence right now is like this
Form component mounts and you also make API request ideally in componentDidMount
It takes data from initialValues prop, which is empty since API response is not yet received.
API request completes and now you have data in state, but even if the state of your component updates, the Form component from Ant Design will not re-render because it already received the initialValues on mount.
Solution:
You should hide the form and ideally show a loader while the initial data is still being fetched. The code will look something like this
if(isLoading) return <div>Loading...</div>
else return <Form
form={form}
// Rest of your component code

Fetch graphql query result on render and re-renders BUT LAZILY

I have a React Apollo app and what I am trying to do is that I have a component that renders some data using charts. For this data, I have some filters that I save in the local state of the component (Using hooks)
const [filters, setFilters] = useState(defaultFilters);
Now what I want is that whenever the component mounts, fetch the data using the default filters. But I also want to re-fetch data when the user updates the filters AND CLICKS ON SUBMIT and I'd fetch the results using new filters.
Since I also want to fetch the results on filter update, I am using useLazyQuery hook provided by apollo
const [getData, {data}] = useLazyQuery(GET_DATA_QUERY, { variables: {filters} });
useEffect(getData, []); // this useEffect runs only when the component mounts and never again
But, what happens is whenever my state, filters, updates the getData function is automatically run! ALWAYS! (BEHIND THE SCENE)
How do I handle such cases, where I want to fetch results on mounting and re-rendering.
I have tried using useQuery and refetch provided by it but I get the same problem there, whenever I update the state, the component rerenders and the useQuery hooks is run and makes the call. (That's how I believe it runs)
How do I fix my current code. Calling the getData function inside the useEffect function makes it run on every re-render.
I think I the problem defined in this stackoverflow-question is somewhat similar to mine.
Part of the problem is that you really have two different states that you're trying to utilize a single hook for. You have state that represents your inputs' values in the UI, and then you have state that represents the filters you want to actually apply to your charts. These are two separate bits of state.
The simplest solution is to just do something like this:
const [inputFilters, setInputFilters] = useState(defaultFilters)
const [appliedFilters, setAppliedFilters] = useState(inputFilters)
const { data } = useQuery(GET_DATA_QUERY, { variables: { filters: appliedFilters } })
const handleSubmit = () => setAppliedFilters(inputFilters)
const handleSomeInputChange = event => setInputFilters(...)
This way, you use inputFilters/setInputFilters only to manage your inputs' state. When the user clicks your submit button, the appliedFilters are set to whatever the inputFilters are at the time, and your query will update to reflect the new variables.

React Hooks: Referencing context and managing dependencies in useEffect hook

I am trying to use react hooks to make a Table component that displays rows of data from an API based on a set of filters that the user can choose. I want to make a new call to fetch data whenever the user clicks an 'Apply Filters' button, not when the user makes changes to the filters.
I am using context to manage the 'filters' state and a 'lastFetched' state which tracks when the user last clicked the 'Apply Filters' button (as well as other states on the page). Updates to the context are made via the useReducer hook and its dispatch method (see here).
The data fetching occurs in a useEffect hook that reruns whenever the 'lastFetched' state changes. This appears to be working correctly; however, the effect references other values from the context (i.e. the filters) that are not included in the dependencies. I am aware of the exhaustive-deps eslint rule, and I am concerned that I am not handling the hook's dependencies correctly.
const Table = () => {
const [context, dispatch] = useTableContext(); // implemented with createContext and useReducer
const { filters, lastFetched } = context;
useEffect(() => {
if (!filters.run) {
return;
}
dispatch({ type: 'FETCH_DATA_BEGIN' });
const params = convertContextToParams(context); // this is lazy, but essentially just uses the the filters and some other state from the context
API.fetchData(params)
.then((data) => {
dispatch({ type: 'FETCH_DATA_SUCCESS', payload: data.results });
})
.catch((e) => {
dispatch({ type: 'FETCH_DATA_FAILURE', payload: e.response.data.message });
});
return () => { ... some cleanup... };
}, [lastFetched]); // <== This is the part in question
return <...some jsx.../>
};
Again, this appears to be working, but according to the react docs, it seems I should be including all the values from the context used in the hook in the hook's dependencies in order to prevent stale references. This would cause the logic to break, since I don't want to fetch data whenever the filters change.
My question is: when the user clicks 'Apply Filters', updates context.lastFetched, and triggers the useEffect hook, will the hook be referencing stale filter state from the context? If so, why? Since the effect is rerun whenever the button is clicked, and all the state updates are done via a reducer, does the usual danger of referencing stale variables in a closure still apply?
Any guidance appreciated!
Note: I have thought about using useRef to prevent this issue, or perhaps devising some custom async middleware to fetch data on certain dispatches, but this is the solution I currently have.
I am not an expert but I would like to provide my takes. According to my understanding of how Context works, you will not get stale filter data with the current implementation. useReducer updates the state with a new object which will trigger Table to be re-render.
Also, Table component doesn't really care about filter data unless lastFetched is changed by a click event. If lastFetched is changed, all the Consumer of TableContext will be re-render again. You should not get stale filter data either.

changing props in react_component when using react_rails

I am using this helper to display a datepicker component
<%= react_component "MyDatePicker", startDate: '', endDate: ''%>
I want to pass javascript values to startDate and endDate props. Any possible way to do this?
I don't really know what you're trying to do here exactly but if you just want to get values of your props from the component to your rails controller, do the following.
You can set state of your props in your react component and send an ajax request whenever the user selects a date.
Fixed this by using Pubsub. What I did is publish the user selected values in the javascript first. Then on react parent component lifecycle method subscribed to the previously published event and use setState to change the state based on that.
Now am on mobile but i will publish the code for clarity once i got access to a pc.
update
Using pubsub is easy. First we need to publish the required from anywhere using javascript
dates={some_value:value, another_value: value }
PubSub.publish(OFFLINE_BOOKING_DURATION, dates)
Here I just pass a dates object. You can pass anything.
Then in react's componentDidMount state I subscribe to this
componentDidMount: function () {
this.token = PubSub.subscribe(OFFLINE_BOOKING_DURATION, this.subscriber)
},
Here the first is object we are expecting and the callback
so here is the call back function here you can do anything like ajax call, set state, or anything
subscriber: function (msg, data) {
#this method gets called on receiving data
#we can access the data we passed like this
data.some_value},
And finally unsubscribe when component unmounts
componentWillUnmount: function () {
PubSub.unsubscribe(this.token)
}
This is how I implemented it. I no longer have the code but I hope you got the point.

Which is better CRUD coding style using Redux?

I have a simple question about coding style for single page application. My front end is using React Redux
For example I have a standard CRUD page where data is displayed in table and pop up modal form. Data table is filtered from the server not from the client.
My question : If i create, update or remove a data should I call a refresh function or just edit it in redux store?
Refresh function :
Data always updated
Newly added data is filtered
Two times request, slower, unresponsive (Main problem)
Redux store:
App looks responsive
One time request
Lost server side filter function and data is not updated if multiple users is using the app (Main Problem)
Any advice will be appreciated
Edit the store locally to give immediate feedback, then send the request and when you get the reply back consolidate the store with the new data
basically, do both things and get the best benefit of both worlds
Dispatch an async action which queries the server where filter happens and when it resolves, update redux state with the refreshed, filtered data.
Pseudocode
// dispatches an action to refresh data without page reload
export function refreshDataAction() {
return (dispatch, getState) => {
return (
fetch('api/data', options) // fetch the data from server and let it filter
.then(data => dispatch(updateDataAction(data)))
);
};
}
// dispatches an action to update redux state with filtered data
export default function updateDataAction(data) {
return {
type: 'UPDATE_DATA',
...data,
}
}
Then you could just call dispatch(refreshDataAction()). Data is filtered, no page refresh.
Calling refresh in a React application (not only React, but any real-time front-end app) kind of defies whole principal of using React.
What you should do is, whenever there occurs a data-changing operation in your client, you should trigger an API call, that alters your server-side data accordingly. Send the data back to the client (you can send it to all clients, if you fancy web-socket), save it to the Redux state to trigger a re-render.

Categories