Live search with pagination in React.js - reactjs

I want to search in all pages, but my code only search in the current page.
For example I'm in the page 2/5 when I type the name of a tourist who is present in this page it shows me the data,
but when I type a tourist which is in the page 4/5 it not show me anything.
I'm using Laravel in backend.
Here's the backend code :
$tourists = Tourist::where('hotel_id', $request->hotel_id)->orderBy('created_at', 'DESC')->paginate(10);
return $toursits;
Frontend code :
this.state = {
activePage: 1,
tourists: []
}
async componentDidMount() {
await this.getTourists();
}
async getTourists() {
let response = await callApi('tourists/paginate', { page: this.state.activePage, hotel_id: this.context.hotel_id[0] });
this.setState({ tourists: response.data, perPage: response.meta.per_page, total: response.meta.total, lastPage: response.meta.last_page });
}
Render method:
{this.state.tourists
.filter(x => new RegExp (this.state.first_name, 'i').test(x.first_name)
.map((tourist, i) =>
<tr>
<td>{tourist.first_name}</td>
</tr>)}

You are getting a paginated list of results from the backend but you are implementing the search functionality on the frontend.
When you first go to your page, you get the first 10 results from your server. At the time, your React application as no idea that there are more results to be parsed and can only "see" the 10 paginated results your are sending from your server. By filtering these results you will not be able to get any other result which was not sent by the server in the first place.
You have 2 solutions:
Implement the pagination client-side,
Implement the search functionality server-side
Given that you already implemented pagination on the server I assume that you have a lot of results and that sending all of them at once would not be practical.
This leaves us with option n°2. Adding to your code example, you could do something like:
$tourists = Tourist::where('hotel_id', $request->hotel_id)
// Add this to filter results by first_name
->where('first_name', 'like', "%{$request->first_name}%"))
->orderBy('created_at', 'DESC')->paginate(10);
return $tourists;

Related

How can I post form data from react to an express.js server and use it as part of a url string

Just to make this clearer. I have a form where the user inputs a name which is passed to the apiUrl const to become part of the URL string. The form input data is passed through state as {this.state.input}. After the user inputs the form with the name he wants to search for, he clicks a button which calls the onButtonSubmit function that fetches the data with the updated apiUrl parameters. The catch is, this is running on the front-end and as this is a proprietary api, I don't want to expose the api key (which is part of the url) to the user.
I have set up an express.js server but I'm still unsure on how I can post the form data to it and then use that in the same manner used in my code below.
onButtonSubmit = () => {
const apiUrl = 'URLStringPart1' + this.state.input + 'URLStringpart2withAPIKey';
fetch(apiUrl)
.then(res => res.json())
.then(
result => {
this.setState({
isLoaded: true,
array1: result.array1,
array2: result.array2,
array3: result.array3,
array4: result.array4,
array5: result.array5,
route: 'fetched'
});
},
error => {
this.setState({
isLoaded: false,
error: error
});
}
);
}
So the output I'm looking for would follow something like this:
Post form data from frontend after the user submits it with a
button click
Through the backend, after the form data is posted, use it to update the apiurl and then fetch the data from the api(using axios perhaps)
Send the fetched data back to the frontend
I think you need to use prams, in your express server the API route should look like this: api/users/:name --> returns user with this name.
Then try fetching this API by sending the request to the server like this:
http://locahost:8000/api/users/${this.state.name}

How to normalize the response API using Normalizr?

I'm making a ReactJs Application using API from the back-end. I did it, but my solution to find the data to display on the app make it slowly.
Ex: I want to get {id, name, color} from the response API I must do like this.
if (meId && list.HasCalendar && list.Calendar && list.Calendar !== {}) {
Object.keys(list.Calendar).forEach((key) => {
const newCalendar = {
bgColor: list.HasCalendar[meId].items[key].data.backgroundColor,
color: list.HasCalendar[meId].items[key].data.colorId,
id: key,
name: list.Calendar[key].data.name
};
array.push(newCalendar);
});
}
array is used to display. I have some API must using 3 loops to find the data. I researched the performance problem and know that I can normalize responses to get data faster. I tried Normailizr but I still don't know how to make a schema from my response API.
This is my sample code: https://codesandbox.io/s/normalizr-gqiit
Can you show me how to deal with this response API? Thanks!

Fetch status 200 but pending endllessly, except first call

I've been searching to solve this problem for a while but couldn't find a working solution.
I'm making a simple social network website and this API returns a article data such as text, image and video url, etc, all saved in server's local MySQL Database. My front-end is React and server is Nginx reverse proxy with Node.js using Express. When I load the page, I create 5 React components that each make fetch request for given article number.
The following code snippet is the fetch API that asks the server to fetch data from database:
//server-side script
app.get('/api/getArticle/:id', (req, res) => {
const con = mysql.createConnection({
host: 'myhost_name',
user: 'myUser',
password: 'myPassword',
database: 'myDB',
});
con.connect(function (err) {
if (err) {
throw err;
}
console.log("Connected!");
})
const idInterest = req.params.id.toString();
console.log(idInterest)
let sql = 'some_sql';
con.query(sql, function (err, result) {
if (err) {
res.status(500).send("Error while getting article data");
return;
}
else {
res.set('Connection', 'close')
res.status(200).send(result);
console.log("ended")
con.end();
return;
}
})
}
//React script
//index.js
fetch('http://mywebsite.com/api/getMaxArticleId/')//Retrieve top 5 article ID
.then((response) => {
for (let i = 0; i < data.length; i++) {
nodesList.push(<Container articleId={data[i]['id']}/>)
}
ReactDOM.render(<React.StrictMode><NavBar />{nodesList}<Writer writer="tempWriter" /></React.StrictMode>, document.getElementById('root'));
})
//Container.jsx; componentDidMount
const url = "http://mywebsite.com/api/getArticle/" + this.props.articleId.toString();
fetch(url, {
method: 'GET',
credentials: "include",
}).then((response) => {
response.json().then((json) => {
console.log(json);
//processing json data
This used to work very fine, but suddenly the getArticle/:id calls started to show 200 status but 'pending' in 'time' column in Chrome network tab, endlessly, all except the first*getArticle/:idcall. This prevents my subsequent .then() in each Container from being called and thus my entire tab is frozen.
Link to image of network tab
As you see from the image, all pending fetches are missing 'Content Download' and stuck in 'Waiting(TTFB)', except the first call, which was '39'
I checked the API is working fine, both on Postman and Chrome, the server sends result from DB query as expected, and first call's Json response is intact. I also see that console.log(response.json()) in React front-end shows Promise{<pending>} with *[[PromiseStatus]]: "Resolved"* and *[[PromiseValue]]* of Array(1) which has expected json data inside.
See Image
This became problematic after I added YouTube upload functionality with Google Cloud Platform API into my server-side script, so that looks little suspicious, but I have no certain clue. I'm also guessing maybe this could be problem of my React code, probably index.js, but I have no idea which specific part got me so wrong.
I've been working on this for a few days, and maybe I need common intelligence to solve this (or I made a silly mistake XD). So, any advices are welcomed :)

Material-ui table pagination

I am using Material-ui table for listing data. table will load all data at once from remote server. Is there any way to load data through pagination, as page changes data has to be fetched from remote.
when page loads i will get data from following code.
const options = { method: 'GET', headers: { Origin: '*' } };
fetch(`https://some-url/user_groups`, options)
.then(function (result) {
//i will get data here
})
.catch(error => console.log('error while fetching ', error));
Follow following steps:
Step 1. Change the server side to return only 1 page of data, and also return number of available records.
/api/getData?offset=5&limit=10
Step 2. On your react components, or redux store, create following state:
{
data: list of data item to display on the table
page: the current page of the table
resultCount: number of available records
}
Step 3. Implement loadData to load the current page of data & result count.
Step 4. On component mount & page change event, reload the data.
yes you can by adding condition to the pagination slicing logic
rows.slice((useDbPagination ? 0 : page) * rowsPerPage,
(useDbPagination ? 0 : page) * rowsPerPage + rowsPerPage).map(/*render row here*/);

Apollo Client cache

I just started using apollo client on a React application and I'm stuck on caching.
I have a home page with a list of products where I do a query to get the id and name of those products and a product page where I do query for the ID, name, description and image.
I would like that if a user visits the home page fist then a specific product page to only do a query for that product's description and image, also display the name during the loading (since I should have cached it already).
I followed "Controlling the Store" part of the documentation (http://dev.apollodata.com/react/cache-updates.html) but still couldn't resolve it.
The query that is done when we go to the product page still asks for both the product's id and name whereas they should be cached since I already asked for them.
I think I'm missing something but I can't figure it out.
Here is a bit of the code:
// Create the apollo graphql client.
const apolloClient = new ApolloClient({
networkInterface: createNetworkInterface({
uri: `${process.env.GRAPHQL_ENDPOINT}`
}),
queryTransformer: addTypename,
dataIdFromObject: (result) => {
if (result.id && result.__typename) {
console.log(result.id, result.__typename); //can see this on console, seems okey
return result.__typename + result.id;
}
// Make sure to return null if this object doesn't have an ID
return null;
},
});
// home page query
// return an array of objects (Product)
export default graphql(gql`
query ProductsQuery {
products {
id, name
}
}
`)(Home);
//product page query
//return an object (Product)
export default graphql(gql`
query ProductQuery($productId: ID!) {
product(id: $productId) {
id, name, description, image
}
}
`,{
options: props => ({ variables: { productId: props.params.id } }),
props: ({ data: { loading, product } }) => ({
loading,
product,})
})(Product);
And my console output:
The answer to your question actually has two parts:
The client cannot actually tell for sure that these queries resolve to the same object in the cache, because they have a different path. One starts with products, the other with product. There's an open PR for client-side resolvers, which will let you give the client hints about where to find things in the cache, even if you haven't explicitly queried for them. I expect that we will publish that feature within a week or two.
Even with client-side resolvers, Apollo Client won't do exactly what you described above, because Apollo Client no longer does query diffing since version 0.5. Instead, all queries are fully static now. That means even if your query is in the cache partially, the full query will be sent to the server. This has a number of advantages that are laid out in this blog post.
You will still be able to display the part that's in the cache first, by setting returnPartialData: true in the options.
This question is quite old, however, there is a solution to map the query to the correct location using cacheRedirects
In my project, I have a projects query and a project query.
I can make a cacheRedirect like below:
const client = new ApolloClient({
uri: "http://localhost:3000/graphql",
request: async (operation) => {
const token = await localStorage.getItem('authToken');
operation.setContext({
headers: {
authorization: token
}
});
},
cacheRedirects: {
Query: {
project: (_, { id }, { getCacheKey }) => getCacheKey({ id, __typename: 'Project' })
}
}
});
Then when I load my dashboard, there is 1 query which gets projects. And then when navigating to a single project. No network request is made because it's reading from the cache 🎉
Read the full documentation on Cache Redirects

Resources