Search is an important feature in mobile applications. Instead of displaying every record, a user can enter a keyword and request matching records from the REST API. React Native can send the search value to a PHP API using Fetch, and the PHP API can search the MySQL database.
API search means sending a search keyword to the server and receiving only the records that match that keyword.
React Native
↓
Search Keyword
↓
PHP REST API
↓
MySQL Search
↓
JSON Response
↓
FlatList
A search keyword can be sent as a query parameter.
GET /api/students.php?search=rahul
Here, search is the parameter and rahul is the search value.
useState can store the text entered by the user.
const [search, setSearch] =
useState("");
Every time the user types, the search state can be updated.
<TextInput
value={search}
onChangeText={setSearch}
placeholder="Search students..."
/>
TextInput provides the search field for the user.
const response = await fetch(
`${API_URL}?search=${search}`
);
const result =
await response.json();
setStudents(
result.data || []
);
Search text may contain spaces or special characters. Encode it before adding it to a URL.
const query =
encodeURIComponent(search);
const response = await fetch(
`${API_URL}?search=${query}`
);
This helps create a valid URL when the search contains special characters.
$search = trim(
$_GET['search'] ?? ''
);
The PHP API can use this value to build the database search condition.
MySQL LIKE can be used to find records containing a particular keyword.
SELECT id, name, email
FROM students
WHERE name LIKE ?
The search value can be provided as a prepared statement parameter.
A search can check more than one column.
SELECT id, name, email, course
FROM students
WHERE name LIKE ?
OR email LIKE ?
OR course LIKE ?
This allows one keyword to search multiple fields.
$keyword = "%" . $search . "%";
$stmt = $pdo->prepare(
"SELECT id, name, email, course
FROM students
WHERE name LIKE ?
OR email LIKE ?
OR course LIKE ?"
);
$stmt->execute([
$keyword,
$keyword,
$keyword
]);
The PHP API can return the matching records as JSON.
{
"success": true,
"data": [
{
"id": 1,
"name": "Rahul Kumar",
"email": "rahul@example.com",
"course": "React Native"
}
]
}
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
</View>
)}
/>
The user can press a button to send the search request.
<Button
title="Search"
onPress={searchStudents}
/>
async function searchStudents() {
const query =
encodeURIComponent(search);
const response =
await fetch(
`${API_URL}?search=${query}`
);
const result =
await response.json();
setStudents(
result.data || []
);
}
The application should decide what to do when the search box is empty.
async function searchStudents() {
if (search.trim() === "") {
loadStudents();
return;
}
// Perform search...
}
In this example, an empty search loads all students.
const [loading, setLoading] =
useState(false);
async function searchStudents() {
setLoading(true);
try {
const query =
encodeURIComponent(search);
const response =
await fetch(
`${API_URL}?search=${query}`
);
const result =
await response.json();
setStudents(
result.data || []
);
} catch (error) {
console.log(
error.message
);
} finally {
setLoading(false);
}
}
async function searchStudents() {
setLoading(true);
setError("");
try {
const query =
encodeURIComponent(search);
const response =
await fetch(
`${API_URL}?search=${query}`
);
const result =
await response.json();
if (!response.ok) {
throw new Error(
result.message ||
"Search failed"
);
}
setStudents(
result.data || []
);
} catch (error) {
setError(
error.message
);
} finally {
setLoading(false);
}
}
A search can also be triggered automatically when the search value changes.
useEffect(() => {
if (search.trim() === "") {
loadStudents();
return;
}
searchStudents();
}, [search]);
For real applications, automatic searching should usually be combined with debouncing so that an API request is not sent for every keystroke.
Debouncing waits for the user to stop typing before making the API request.
useEffect(() => {
const timer =
setTimeout(() => {
if (search.trim() === "") {
loadStudents();
} else {
searchStudents();
}
}, 500);
return () =>
clearTimeout(timer);
}, [search]);
The 500 millisecond delay is an example and can be adjusted.
Search can be combined with pagination when the result contains many records.
GET /api/students.php
?search=rahul
&page=1
&limit=10
The PHP API can use the search value together with LIMIT and OFFSET.
If the search endpoint is protected, the React Native application can send the JWT token.
const response = await fetch(
`${API_URL}?search=${query}`,
{
headers: {
"Accept":
"application/json",
"Authorization":
`Bearer ${token}`
}
}
);
<TextInput
value={search}
onChangeText={setSearch}
placeholder="Search students..."
/>
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
{item.email}
</Text>
</View>
)}
ListEmptyComponent={
<Text>
No matching students found.
</Text>
}
/>
<?php
header(
"Content-Type: application/json"
);
require_once "../db.php";
$search = trim(
$_GET['search'] ?? ''
);
$keyword = "%" . $search . "%";
$stmt = $pdo->prepare(
"SELECT id, name, email, course
FROM students
WHERE name LIKE ?
OR email LIKE ?
OR course LIKE ?
ORDER BY id DESC"
);
$stmt->execute([
$keyword,
$keyword,
$keyword
]);
$data =
$stmt->fetchAll(
PDO::FETCH_ASSOC
);
echo json_encode([
"success" => true,
"data" => $data
]);
The prepared statement keeps the search value separate from the SQL command.
async function searchStudents() {
setLoading(true);
setError("");
try {
const query =
encodeURIComponent(
search.trim()
);
const response =
await fetch(
`${API_URL}?search=${query}`
);
const result =
await response.json();
if (!response.ok) {
throw new Error(
result.message ||
"Search request failed"
);
}
if (!result.success) {
throw new Error(
result.message ||
"Unable to search"
);
}
setStudents(
result.data || []
);
} catch (error) {
setError(
error.message
);
} finally {
setLoading(false);
}
}
The API can also return the number of matching records.
{
"success": true,
"data": [
{
"id": 1,
"name": "Rahul"
}
],
"meta": {
"total": 1
}
}
React Native can display the total result count.
<Text>
Results: {total}
</Text>
import React, {
useEffect,
useState
} from "react";
import {
View,
Text,
TextInput,
FlatList,
ActivityIndicator
} from "react-native";
const API_URL =
"https://example.com/api/students.php";
export default function StudentSearch() {
const [search, setSearch] =
useState("");
const [students, setStudents] =
useState([]);
const [loading, setLoading] =
useState(false);
const [error, setError] =
useState("");
async function searchStudents(
keyword = search
) {
setLoading(true);
setError("");
try {
const query =
encodeURIComponent(
keyword.trim()
);
const response =
await fetch(
`${API_URL}?search=${query}`
);
const result =
await response.json();
if (!response.ok) {
throw new Error(
result.message ||
"Search failed"
);
}
if (!result.success) {
throw new Error(
result.message ||
"Unable to search"
);
}
setStudents(
result.data || []
);
} catch (error) {
setError(
error.message
);
} finally {
setLoading(false);
}
}
useEffect(() => {
const timer =
setTimeout(() => {
searchStudents();
}, 500);
return () =>
clearTimeout(timer);
}, [search]);
return (
<View>
<TextInput
value={search}
onChangeText={setSearch}
placeholder=
"Search students..."
/>
{loading && (
<ActivityIndicator
size="small"
/>
)}
{error !== "" && (
<Text>
{error}
</Text>
)}
<FlatList
data={students}
keyExtractor={item =>
item.id.toString()
}
renderItem={({ item }) => (
<View>
<Text>
Name:
{item.name}
</Text>
<Text>
Email:
{item.email}
</Text>
<Text>
Course:
{item.course}
</Text>
</View>
)}
ListEmptyComponent={
!loading ? (
<Text>
No matching
students found.
</Text>
) : null
}
/>
</View>
);
}
React Native
↓
TextInput
↓
Search Keyword
↓
URL Encode
↓
Fetch
↓
GET /students.php?search=rahul
↓
PHP API
↓
Validate
↓
Prepared SQL
↓
MySQL
↓
Matching Records
↓
JSON Response
↓
setStudents()
↓
FlatList
↓
Display Results
This pattern can be extended with pagination, sorting, filtering, authentication, and TypeScript API types.
Question: Which query parameter can commonly be used to send a search keyword to a REST API?