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.
Related
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])
I have an API call, that is returning two objects: data and pageOutput.
{
data: "[{"title":["Travis Jackson HOF 1931 W517 # 12 - SGC 50"],"image":["https://i.ebayimg.com/00/s/MTYwMFg5NzY=/z/uU8AAOSwMtdd3ZXo/$_1.JPG"],"itemURL":["https://rover.ebay.com/rover/1/711-53200-19255-0/1?ff3=2&toolid=10044&campid=5338164673&customid=vintagebaseball&lgeo=1&vectorid=229466&item=133253226463"]"
pageOutput: "{"pageNumber":["1"],"entriesPerPage":["100"],"totalPages":["2"],"totalEntries":["194"]}"
}
I have a reducer that is fetching the data from my API and storing data in a a state called 'baseball' like this. Note it is just storing the 'data' piece from my API call.
const baseballReducer = (state = [], action) => {
switch (action.type) {
case "INIT_BLOGS":
return action.data;
export const initializeBaseball = () => {
return async dispatch => {
const baseballCards = await baseballService.getAll();
dispatch({
type: "INIT_BLOGS",
data: JSON.parse(baseballCards.data)
});
};
};
I need to get the pageOutput into a separate state. Now i know that i could create a separate page reducer, make a call to the api and store that pageOutput data in a new state. However, i think that it would be bad practice to make two different calls to the API?
Is there a better way? I was thinking of just storing all of the data (including the pageOutput) in the baseball state, but then I'm not sure if this is best practice or not, especially considering that I have a Pagination control that needs the updated active page to requery the database. Hope this is clear enough--happy to provide any additional code.
There is no need to make two api calls as you already have all data available in a single api call.
Basically you can:
Have two reducers listening to the same dispatched action, each reducer receiving a different portion of the total api response by destructuring the payload to the relevant property (data / pageOutput)
Dispatch two separate actions altogether, one for each reducer.
It doesn't really matter to the app which one you use, so imo it comes down to personal taste.
If you have control over the backend api, I would probably handle pagination a bit differently. Pagination state can be handled fully at the client, and the api would just respond to the client's request (limit / offset - or pageNr, perPage query parameters depending on your taste).
Even though you could therefore return meta data in the api response, you wouldn't need to depend on the api response to manage your state (frontend state change from page1 -> page2 would depend on clicking page2 and configurations defined by the client, not on the response of the api).
I have a sort of Dashboard in my application. In this dashboard I let the user put many widgets (each widget is a class component). Each widget renders different stuff, such as, charts, images, and text. When I display it, each widget make an axios call to retrieve data from backend. I need a way to be able to tell when all the requests have finished so I can get the HTML completely rendered (I'm going to export it using HiqPdf later).
I need each widget to be independent so I can use in other components. That's why each widget make its own axios call. Otherwise I think I could make many axios calls in a single component that is above my widgets and then I would pass all the data as props to each widget. However, no... the axios calls must stay inside each widget.
I've found many places talking about promises, but every example talks show how to do it in a single component.
The reason I'm working on it is because I have the need to export it using a library call HiqPdf. This library receives a HTML as string and exports to PDF. Therefore, I need to know when the dashboard has been completely loaded to let the application export it.
Think about an event-driven framework that persists the global state of your single page app and notify subscribers whenever there is a change in the state.
One of the famous frameworks is redux.
Another simple framework is mufa. These are some similar questions that leverages mufa:
https://stackoverflow.com/a/42124013/747579
Stop the communication between react components using mufa after a condition
For your case, it might be something like this:
const all_calls = [];
const {on, one, fire, unsub} = mufa;
axios.get('call1').then((data) => {
fire('call1_received', data);
})
axios.get('call2').then((data) => {
fire('call2_received', data);
});
one('call1_received', () => {
all_calls.push('call1_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
one('call2_received', () => {
all_calls.push('call2_received');
if (all_calls.length === 2) {
alert('!!!! All calls have been received')
}
})
Note, one will subscribe once only.. while on subscribe forever.
So, I have an app that user can choose several settings in. Like number format or a currency that will be displayed by default.
For that there is a special API endpoint /settings that I get the values from.
The whole app is rendered on the server side when the user reloads the page. I fire the settings fetch as soon as possible (in the componentWillMount of the top level component), but there is sometimes a blink/ delay.
Possible solutions:
First solution is to fetch the settings when the user loads the app for the first time, and save it in the localStorage if it's available. Downside is that the numbers/ currencies still can be different than those in the settings when the app is loaded for the first time.
Second solution would be to fetch the data before the application is rendered on the server side, and inject this data somewhere into script tag (like a window.userSettings = { ...settings }). It might extend the reload loading time a bit, but the settings will be as the user set them.
Is there any other solution to such a problem? What is the best way to do it?
I hope, this solution may help you.
step 1: Perform API call in componentWillMount and also, check for error. Assign two state one for currencies and one for error, if possible another one for loading
Step 2: Assign localStorage using your state in componnetDidMount
Step 3: Then, under your render method, check for both error state and localStorage
Sample snippet in given below
class App extends Component{
custructor(props){
super(props);
this.state={
currency_number: '',
error: false
}
}
componentWillMount(){
//perform fetch api and assign the state with the received items
// check for error, if so then setState({error: true})
}
ComponentDidMount(){
localStorage.setItem('currency', JSON.stringify(this.state.currency_number))
}
render(){
const currency = JSON.parse(localStorage.getItem('currency'))
if (this.state.error) {
return(
<div>
{ currency }
</div>
)
}
}
}
I have an application which searches for flights using Vue.js and Vue Router.
I have two components, first one is search, which is on the base route '/'. When user clicks on search, it will send a request to server and gets a huge list of flights.
Then I need to call the result component on '/results' route and show the results using v-for.
I have two questions, first, how can I manually redirect to '/results' after I get the results.
Second and more important, what is the proper way of passing the results data to results component to use?
Inside your results components, you can put transition hooks in the route object. Read here: http://vuejs.github.io/vue-router/en/pipeline/hooks.html
The activate hook runs when a component is activated, and the component wont appear until the activate hook has run. Here's the example on that page, which would be similar to yours:
route:{
activate: function (transition) {
return messageService
.fetch(transition.to.params.messageId)
.then((message) => {
// set the data once it arrives.
// the component will not display until this
// is done.
this.message = message
})
}
}
So basically when they click search you send them to /results and this hook will handle loading the data in between.
Here's an advanced example of a mail app using vue-router that shows off a lot of the transition hooks in action: https://github.com/vuejs/vue-router/tree/dev/example/advanced