Membuat Aplikasi Bookmark Website dengan React: Panduan Lengkap
Bookmark manager adalah alat penting untuk mengorganisir situs favorit. Di tutorial ini, kita akan membangun aplikasi bookmark website dengan React yang memiliki:
✅ Fitur CRUD lengkap (Create, Read, Update, Delete)
✅ Penyimpanan lokal menggunakan browser localStorage
✅ Tampilan responsive
✅ Pencarian & filter bookmark
✅ UI modern dengan animasi
Yang akan Anda pelajari:
-
Manajemen state dengan React Hooks
-
Penyimpanan data di localStorage
-
Pembuatan komponen reusable
-
Validasi form
-
Error handling
🛠 Persiapan Project
1. Membuat Project React
npx create-react-app bookmark-app
cd bookmark-app
2. Install Dependencies
npm install react-icons uuid
3. Struktur Folder
src/ ├── components/ │ ├── BookmarkForm.jsx │ ├── BookmarkList.jsx │ └── SearchBar.jsx ├── App.js ├── App.css └── index.js
💻 Implementasi Kode
1. Komponen Utama (App.js)
import { useState, useEffect } from 'react'; import BookmarkForm from './components/BookmarkForm'; import BookmarkList from './components/BookmarkList'; import SearchBar from './components/SearchBar'; import './App.css'; function App() { const [bookmarks, setBookmarks] = useState([]); const [searchTerm, setSearchTerm] = useState(''); // Load data dari localStorage saat komponen mount useEffect(() => { try { const saved = JSON.parse(localStorage.getItem('bookmarks')) || []; setBookmarks(saved); } catch (error) { console.error("Gagal memuat bookmark:", error); setBookmarks([]); } }, []); // Simpan ke localStorage saat bookmarks berubah useEffect(() => { try { localStorage.setItem('bookmarks', JSON.stringify(bookmarks)); } catch (error) { console.error("Gagal menyimpan bookmark:", error); } }, [bookmarks]); const addBookmark = (newBookmark) => { setBookmarks([...bookmarks, { ...newBookmark, id: Date.now() }]); }; const deleteBookmark = (id) => { setBookmarks(bookmarks.filter(bookmark => bookmark.id !== id)); }; // Filter bookmark berdasarkan pencarian const filteredBookmarks = bookmarks.filter(bookmark => bookmark.title.toLowerCase().includes(searchTerm.toLowerCase()) || bookmark.url.toLowerCase().includes(searchTerm.toLowerCase()) ); return ( <div className="app"> <h1>Bookmark Manager</h1> <BookmarkForm onAdd={addBookmark} /> <SearchBar searchTerm={searchTerm} onSearch={setSearchTerm} /> <BookmarkList bookmarks={filteredBookmarks} onDelete={deleteBookmark} /> </div> ); } export default App;
2. Komponen BookmarkForm
import { useState } from 'react'; import { FaPlus } from 'react-icons/fa'; const BookmarkForm = ({ onAdd }) => { const [title, setTitle] = useState(''); const [url, setUrl] = useState(''); const handleSubmit = (e) => { e.preventDefault(); if (!title || !url) { alert('Judul dan URL harus diisi!'); return; } if (!url.startsWith('http')) { alert('URL harus dimulai dengan http:// atau https://'); return; } onAdd({ title, url }); setTitle(''); setUrl(''); }; return ( <form onSubmit={handleSubmit} className="bookmark-form"> <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Judul Bookmark" required /> <input type="text" value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://contoh.com" required /> <button type="submit"> <FaPlus /> Tambah </button> </form> ); }; export default BookmarkForm;
3. Komponen BookmarkList
import { FaTrash, FaExternalLinkAlt } from 'react-icons/fa'; const BookmarkList = ({ bookmarks, onDelete }) => { if (!bookmarks) return <div>Memuat bookmark...</div>; return ( <div className="bookmark-list"> {bookmarks.length === 0 ? ( <p>Tidak ada bookmark</p> ) : ( <ul> {bookmarks.map(bookmark => ( <li key={bookmark.id}> <div className="bookmark-info"> <h3>{bookmark.title}</h3> <a href={bookmark.url} target="_blank" rel="noopener noreferrer" > {bookmark.url} <FaExternalLinkAlt /> </a> </div> <button onClick={() => onDelete(bookmark.id)} className="delete-btn" > <FaTrash /> </button> </li> ))} </ul> )} </div> ); }; export default BookmarkList;
4. Komponen SearchBar
const SearchBar = ({ searchTerm, onSearch }) => { return ( <div className="search-bar"> <input type="text" value={searchTerm} onChange={(e) => onSearch(e.target.value)} placeholder="Cari bookmark..." /> </div> ); }; export default SearchBar;
Styling dengan CSS
/* App.css */ .app { max-width: 800px; margin: 0 auto; padding: 2rem; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } h1 { text-align: center; color: #2c3e50; margin-bottom: 2rem; } /* Form Style */ .bookmark-form { display: flex; gap: 1rem; margin-bottom: 2rem; } .bookmark-form input { flex: 1; padding: 0.8rem; border: 2px solid #ddd; border-radius: 8px; font-size: 1rem; transition: all 0.3s; } .bookmark-form input:focus { outline: none; border-color: #3498db; box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } .bookmark-form button { background: #3498db; color: white; border: none; padding: 0 1.5rem; border-radius: 8px; cursor: pointer; font-weight: bold; transition: background 0.3s; } .bookmark-form button:hover { background: #2980b9; } /* Bookmark List Style */ .bookmark-list ul { list-style: none; padding: 0; } .bookmark-list li { display: flex; justify-content: space-between; align-items: center; padding: 1.2rem; margin-bottom: 1rem; background: white; border-radius: 10px; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); transition: transform 0.2s; } .bookmark-list li:hover { transform: translateY(-3px); } .bookmark-info h3 { margin: 0 0 0.5rem 0; color: #2c3e50; } .bookmark-info a { color: #7f8c8d; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; } .bookmark-info a:hover { color: #3498db; } .delete-btn { background: none; border: none; color: #e74c3c; cursor: pointer; font-size: 1.2rem; transition: color 0.2s; } .delete-btn:hover { color: #c0392b; } /* Search Bar Style */ .search-bar { margin-bottom: 2rem; } .search-bar input { width: 100%; padding: 0.8rem; border: 2px solid #ddd; border-radius: 8px; font-size: 1rem; } /* Responsive Design */ @media (max-width: 768px) { .bookmark-form { flex-direction: column; } .app { padding: 1rem; } }
Preview Aplikasi
Kesimpulan
-
Tambah Bookmark
-
Validasi URL otomatis
-
Penyimpanan instan ke localStorage
-
-
Kelola Bookmark
-
Hapus bookmark dengan satu klik
-
Buka link di tab baru
-
-
Pencarian Cepat
-
Filter berdasarkan judul atau URL
-
Pencarian real-time
-
-
Penyimpanan Lokal
-
Data tetap ada setelah refresh
-
Error handling untuk localStorage
-