Reactjs - getting data from server and updating - javascript

(reactjs newbie here)...
I'm using Reactjs to create a page where I have
a simple search box
user types in a search text
data is fetched from the server and is displayed
Now, the "searchText" and "data" are my states and I'm trying to figure out how to update the "results" only after the data is received from the server.
I have an event where I handle whenever user types something as a search text
handleUserInput: function(searchText) {
this.loadDataFromServer(searchText);
this.setState({
searchText: searchText,
});
},
But with the above function, the following thing happens
Initial data is loaded
User types in something
The result is IMMEDIATELY updated to only show the the result that contains the search text (code below), BUT at the same time a request is made to the server to fetch results where the result contains the search text
this.props.products.forEach(function(product) {
if(product.name.toLowerCase().indexOf(this.props.searchText) > -1) {
row =
rows.push(row)
}
}.bind(this));
After about a second, new data is received from the server and the result is refreshed again.
Obviously what I want to do is
Load initial data
User types search text
Request data from the server
Receive data from the server
Update the results
What is the proper way of achieving this?

Don't think searchText should be a state itself. You could just use data fetched from the server to set the state.
Let's say, data is a state property. you could pass a callback to the loadDataFromServer and loadDataFromServer calls this callback once data is fetched on it's onsuccess.
this.loadDataFromServer(searchText, function(data) {
this.setState({data: data}};
});
This way, the component will rerender and show the results, once the data is updated.

So, it is just the first refresh that you want to stop right?
If it is already refreshing once the results come from the server, it seems that all you need to do is not filter the results on the client in step 3 - then the same virtual DOM will be generated as in the first place, so the result list will only update the actual DOM once the server responds.

Related

How do I hide a load more button when data coming from api is empty using react and redux

GitHub link : https://github.com/rakeshvora2007/github-search-using-react
I am able to create an action using SerachBar.js and send it to reducer and then displaying using UserGithubHandle.js, also I am sending an initial page for first user using searchBar.js.
After displaying the user I am able to show the loadmore button when clicked increments the page number and gets the next payload from api using function loadMoreUserFollower from ../actions/index.js which then passes the data to reducer which takes the previous data and new data and send it to UserFollower.js. Now the USerFollower.js dispplays the data.
Problem is once the data coming in has ended the loadMore button should not be displayed. How do I do it using react and redux pattern.
I found the solution.
When data is coming from reducer to UserFollower.js check for the size of data coming in and based on that setState of isHidden to true if incoming data is less than expected or else it is false. Load more button is displayed based on state of isHidden

ajax call only once on first time click of an element

I am designing a chatting application just like WhatsApp web . in that right now I have dummy data for chats. so suppose, if I click on any chat then corresponding chat logs are displayed but these chat logs are dummy data. same way I have done for other chats also but now what I want is if I click on any of the chat then an ajax call should happen and chat logs are rendered and displayed dynamically but this ajax call should happen only one for every chat that means if I click for first time on some chat an ajax call should happen but if click the second time no ajax call should happen.
any suggestions..?
Question: I understood that, once you click on a chat and got data, from the next time ajax call should not be made which will be an extra call.
Solution: The solution for your question will be, first time when you get response from the server, save it in localStorage, A localStorage is a powerful feature of browser which stores data in the browser session.
Implemenatation:
An example api call,
$.post(
"chat-api-url",
{ chat: "chatId" },
function(data) {
localStorage.setItem('chatId', 'data')
}
);
So, now after click in jquery check condition,
if(localStorage.getItem('chatId') == undefined)
{
$.post(
"chat-api-url",
{ chat: "chatId" },
function(data) {
localStorage.setItem('chatId', data)
this.chatData = data;
}
);
} else{
this.chatData = localStorage.getItem('chatId');
}
PS:
localStorage.setItem stores into localstorage
localStorage.getItem retrieves from. localstorage
Here is a documeantation regarding different storages

Vue.js merge data without a re-render?

I have a search component that gets its data in the form as a prop of PHP json_encoded data:
<search :data="<?= json_encode($jsonHotels) ?>"></search>
This way it receives the first 25 movies straight away when the page renders.
After this I make an ajax request to fetch the rest of the result if there are more than 25 movies.
The problem is that when I override the data with the data from the AJAX call, the component re-renders.
Previously to combat this I performed an ajax request with an offset of 25 to skip the first 25 movies and only give me the extra results. Pushing this onto the array didn't cause a re-render and this worked perfectly.
That was perfect, until I got to thinking:
What about people who start or refresh the page while they are on page number 2-3-4-5-etc.
I now have to not only mess with my offset, but I also have to possibly prepend data to my array and well as possibly append data with a push.
Is there a way to merge data without causing a re-render? I am wondering if anyone else has every run into the problem.
Simply fetching all results with an AJAX request takes too long and obviously also causes a re-render. Not fetching initial backend data would mean people would be starting at a blank page or a spinner for 2-3 seconds.
Edit:
Ended up with this:
mergeData(state) {
// Smart merge ajaxData and hotels.
const offSet = state.currentPage * state.itemsPerPage;
const start = state.ajaxData.slice(0, offSet - state.itemsPerPage);
const end = state.ajaxData.slice(offSet);
state.data.unshift(...start);
state.data.push(...end);
},
Pretty much slice my array in 2 and remove the currentPage section. By using unshift and push I prevent a re-render from happening.
Remember that your viewmodel is a model of your view. Here, you're not modeling your application, you're just trying to plug your data in.
If you want to display a page of results at a time, have some kind of model for a page of results. When you fetch your data, put it into the appropriate model-pages. Since you're only displaying one page at a time, populating other pages will not cause a re-render.

Sending extra, non-model data in a save request with backbone.js?

I'm looking for a solution for dealing with an issue of state between models using backbone.js.
I have a time tracking app where a user can start/stops jobs and it will record the time the job was worked on. I have a job model which holds the job's data and whether it is currently 'on'.
Only 1 job can be worked on at a time. So if a user starts a job the currently running job must be stopped. I'm wondering what the best solution to do this is. I mean I could simply toggle each job's 'on' parameter accordingly and then call save on each but that results in 2 requests to the server each with a complete representation of each job.
Ideally it would be great if I could piggyback additional data in the save request similarly to how it's possible to send extra data in a fetch request. I only need to send the id of the currently running job and since this really is unrelated to the model it needs to be sent alongside the model, not part of it.
Is there a good way to do this? I guess I could find a way to maintain a reference to the current job server side if need be :\
when you call a save function, the first parameter is an object of the data that's going to be saved. Instead of just calling model.save(), create an object that has the model data and your extra stuff.
inside of your method that fires off the save:
...
var data = this.model.toJSON();
data.extras = { myParam : someData };
this.model.save(data, {success: function( model, response ) {
console.log('hooray it saved: ', model, response);
});
...

Applying filter to my store causes grid to refresh with incorrect data set temporarily

I have a very simple interface containing a grid, a search field, a search button and a data store from a JSON data source.
The default state of the grid is showing all the data for the given user and entering a term in the search field and clicking the search button applies a filter which then re-executes a call to fetch a new JSON result set and put that data in the grid. I'm doing so the following way:
quick_search: function(search_term, store) {
store.clearFilter(true);
store.filter([{property: 'filter', value: search_term}]);
}
The following function is executed just fine when the search button is clicked, but I'm seeing this scenario:
User starts with 100 records in the grid
User searched for "test" (has 25 records)
The appropriate 25 records show in the grid
User then searches for "stack" (45 results)
The grid quickly shows the original 100 records momentarily and then shows the correct 45 records
And when that last step occurs, it's a very quick blip.
Is this the correct pattern for re-freshing grid data on the fly in a search-esque way? Am I perhaps incorrectly clearing the filter?
Found the solution... Previous solution was trying to run load and was resulting in multiple requests back to my webserver fetching multiple result sets (first the incorrect, then the correct).
quick_search: function(search_term, store) {
store.filters.clear();
store.filter([{property: 'filter', value: search_term}]);
}

Categories

Resources