import { navLinks } from "../../../data/links"
import LogoImg from "../../../assets/images/logo.png"
import { Link } from "react-router-dom"
import { useState } from "react";
import { useNavigate } from "react-router-dom";
function Navbar() {
const [query, setQuery] = useState("");
const navigate = useNavigate();
const handleSubmit = (e) => {
e.preventDefault();
const cleanQuery = query.trim();
if (!cleanQuery) return;
navigate(`/search?q=${cleanQuery}`);
};
return (
<div className="shadow-sm">
<nav className="navbar navbar-expand-lg bg-body-tertiary">
<div className="container">
<a className="navbar-brand" href="/">
<img src={LogoImg} alt="logo" width="40px" />
</a>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav me-auto mb-2 mb-lg-0">
{
navLinks.map((link) => {
return (
<li key={link.id} className="nav-item">
<Link className="nav-link" to={link.link}>{link.title}</Link>
</li>
)
})
}
</ul>
{/* <form className="d-flex" role="search">
<input className="form-control me-2" type="search" placeholder="إبحث" aria-label="Search" />
<button className="btn btn-outline-success" type="submit">إبحث</button>
</form> */}
<form onSubmit={handleSubmit} className="d-flex">
<input
type="text"
className="form-control"
placeholder="ابحث عن كتاب..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button className="btn btn-primary ms-2">
بحث
</button>
</form>
</div>
</div>
</nav>
</div>
)
}
export default NavbarJavaScriptimport { useSearchParams } from "react-router-dom";
import { useSelector } from "react-redux";
import { useMemo } from "react";
import Book from "./Book/Book";
import { useEffect } from "react";
import { useDispatch } from "react-redux";
import { getAllBooks } from "../store/booksSlice";
const Search = () => {
const dispatch = useDispatch();
const [searchParams] = useSearchParams();
const query = searchParams.get("q")?.toLowerCase().trim() || "";
const {data , isLoading , error} = useSelector((state)=> state.books);
const filteredBooks = useMemo(() => {
return data.filter(book =>
book.name.toLowerCase().includes(query)
);
}, [data, query]);
useEffect(() => {
if (data.length === 0) {
dispatch(getAllBooks());
}
}, [data.length, dispatch]);
return (
<div className="container mt-4">
<h3>نتائج البحث عن: "{query}"</h3>
{filteredBooks.length === 0 && (
<p>لا توجد نتائج</p>
)}
<div className="row row-cols-lg-5">
{filteredBooks.map(book => (
<Book book={book}/>
))}
</div>
</div>
);
};
export default Search;JavaScriptالطريقة الثانية:
أولًا: تنفيذ Live Search بدون Debounce (للفهم)
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const NavbarSearch = () => {
const [query, setQuery] = useState("");
const navigate = useNavigate();
useEffect(() => {
const cleanQuery = query.trim();
if (cleanQuery) {
navigate(`/search?q=${cleanQuery}`);
}
}, [query, navigate]);
return (
<input
type="text"
className="form-control"
placeholder="ابحث..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
};JavaScriptالتنفيذ الصحيح باستخدام setTimeout
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const NavbarSearch = () => {
const [query, setQuery] = useState("");
const navigate = useNavigate();
useEffect(() => {
const timeout = setTimeout(() => {
const cleanQuery = query.trim();
if (cleanQuery) {
navigate(`/search?q=${cleanQuery}`);
}
}, 400); // الانتظار 400ms
return () => clearTimeout(timeout);
}, [query, navigate]);
return (
<input
type="text"
className="form-control"
placeholder="ابحث..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
);
};
export default NavbarSearch;JavaScript