مقدمه

اپلیکیشن ما در حال حاضر کاملاً کاربردی است، اما یک مشکل بزرگ دارد: به محض اینکه کاربر صفحه را رفرش می‌کند، تمام وظایف از بین می‌روند. دلیل این امر این است که state ما تنها در حافظه موقت مرورگر ذخیره می‌شود. برای اینکه داده‌های ما ماندگار باشند، باید آنها را در یک مکان پایدارتر ذخیره کنیم.

یک راه حل ساده و بسیار رایج برای این کار در سمت کلاینت، استفاده از Web Storage API مرورگر و به طور خاص، localStorage است. localStorage به ما اجازه می‌دهد تا داده‌ها را به صورت زوج‌های کلید-مقدار در مرورگر کاربر ذخیره کنیم. این داده‌ها حتی پس از بستن و باز کردن مجدد مرورگر نیز باقی می‌مانند.

ذخیره کردن state در localStorage

ما می‌خواهیم هر زمان که لیست todos تغییر می‌کند، نسخه جدید آن را در localStorage ذخیره کنیم. بهترین مکان برای انجام این کار، یک هوک useEffect است که به متغیر state مربوط به todos وابسته باشد.

Copy Icon JAVASCRIPT (React)
import { useState, useEffect } from 'react';

function TodoApp() {
  const [todos, setTodos] = useState([]);

  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  // ... other logic (addTodo, deleteTodo, etc.) ...
}

در این کد، ما یک useEffect اضافه کرده‌ایم که به todos وابسته است. این یعنی هر بار که آرایه todos تغییر می‌کند (یک وظیفه اضافه، حذف یا ویرایش می‌شود)، تابع افکت ما اجرا خواهد شد.

در داخل افکت، ما از localStorage.setItem() برای ذخیره داده‌ها استفاده می‌کنیم. از آنجایی که localStorage تنها می‌تواند رشته‌ها را ذخیره کند، ما ابتدا آرایه todos را با استفاده از JSON.stringify() به یک رشته JSON تبدیل می‌کنیم.

خواندن state از localStorage هنگام بارگذاری اولیه

اکنون که داده‌ها را ذخیره می‌کنیم، باید هنگام بارگذاری اولیه اپلیکیشن، آنها را از localStorage بخوانیم تا state اولیه خود را با آن مقداردهی کنیم.

ما می‌توانیم یک مقدار اولیه را به صورت تنبل (lazily) به useState پاس دهیم. اگر شما یک تابع را به عنوان مقدار اولیه به useState بدهید، React آن تابع را تنها در رندر اولیه اجرا خواهد کرد. این بهترین مکان برای خواندن داده از localStorage است، زیرا این یک عملیات همزمان است و تنها یک بار به آن نیاز داریم.

Copy Icon JAVASCRIPT (React)
function TodoApp() {
  const [todos, setTodos] = useState(() => {
    const savedTodos = localStorage.getItem('todos');
    if (savedTodos) {
      return JSON.parse(savedTodos);
    } else {
      return [];
    }
  });

  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  // ... rest of the component ...
}

در این نسخه نهایی، ما یک تابع را به useState پاس داده‌ایم. این تابع ابتدا با localStorage.getItem('todos') سعی می‌کند داده‌های ذخیره شده را بخواند.

اگر داده‌ای وجود داشته باشد، آن را با JSON.parse() از رشته JSON به آرایه پایتون تبدیل کرده و به عنوان state اولیه برمی‌گرداند. اگر هیچ داده‌ای ذخیره نشده باشد (اولین بازدید کاربر)، یک آرایه خالی را به عنوان مقدار اولیه برمی‌گرداند.

در این درس، با ترکیب هوک‌های useState و useEffect با localStorage API مرورگر، قابلیت ماندگاری را به اپلیکیشن خود اضافه کردیم. اکنون وظایف کاربر حتی پس از بستن تب مرورگر نیز حفظ می‌شوند که این یک گام بزرگ برای بهبود تجربه کاربری است.

اپلیکیشن ما اکنون از نظر عملکردی کامل است. در درس پایانی این فصل و این دوره، به «تقسیم‌بندی پروژه به کامپوننت‌های مجزا» خواهیم پرداخت و با بازسازی نهایی کد، آن را برای نگهداری و توسعه در آینده آماده خواهیم کرد.