Cách tạo Custom React Hook để lưu State vào LocalStorage

0
Dịch vụ dạy kèm gia sư lập trình

Với các ứng dụng Single Page Application (SPA), các state bạn hay lưu vào bộ nhớ tạm như RAM (kể cả dùng Redux). Nên mỗi khi người dùng refresh lại trình duyệt là các state sẽ bị reset lại hết.

Vậy phải làm thế nào để lưu các state ngay cả khi refresh trang hay tắt hẳn tab đó đi?

Thực ra, bạn đã từng làm điều này rồi đấy? Bạn có nhớ tính năng đăng nhập không? bạn lưu token khi người dùng đăng nhập thành công vào đâu?

Câu trả lời đó là localstorage.

Có một vài thư viện 3rd hỗ trợ bạn lưu state vào localstorage một cách đơn giản. Tuy nhiên, các thư viện này cũng sử dụng hook của React để thực hiện lưu mà thôi. Do vậy, tại sao mình không tự viết một hook riêng và có thể tái sử dụng ở bất kỳ đâu trong dự án.

Lưu state trong localstorage sử dụng API mặc định

Dưới đây là một ví dụ minh họa cách bạn lưu dữ liệu vào localstorage và lấy dữ liệu ra để hiển thị. Tất cả được thực hiện bằng Api mặc định của Javascript.

// App.js
export default function App() {
  const [name, setName] = useState(localStorage.getItem("name") || undefined);

  const handleFormChange = (event) => {
    setName(event.target.value);
    localStorage.setItem("name", event.target.value);
  };
  return (
    <div className="App">
      <div className="title">Bản đăng ký thông tin</div>
      <div className="sub-title">@vntalking.com</div>
      <hr></hr>
      <div className="row">
        <div>
          Họ tên:
          <input
            className="input"
            value={name}
            onChange={(e) => handleFormChange(e)}
          />
        </div>
      </div>
    </div>
  );
}

Trong đoạn code trên, mình sử dụng API mặc định của JS như localStorage.setItem để lưu dữ liệu và localStorage.getItem để lấy dữ liệu.

luu-du-lieu-localstorage-api-mac-dinh

Kết quả cuối cùng thì chương trình vẫn chạy đúng như mong muốn. Khi nhập dữ liệu xong và dù có refresh trình duyệt thì giá trị vừa nhập trước đó vẫn giữ được.

Cách làm vẫn ok thôi, nhưng nếu dự án mở rộng ra, ví dụ như: có nhiều input hơn trên màn hình, mỗi input đều tự động lưu dữ liệu vào storage…

Đến đây, chúng ta chắc chắn sẽ muốn viết một giải pháp mà có thể tái sử dụng tốt hơn, tối ưu hơn thay vì viết thủ công như trên.

Giải pháp đó là tạo một custom hook để Persisting State trong React JS.

Tạo Custom Hook để Persist React State

Dưới đây là đoạn tham khảo về tạo một hook để chuyên lưu dữ liệu vào localstorage.

//useLocalStorage.js
export const useLocalStorage = name => {
  const getLocalStorage = () => {
      const local = localStorage.getItem(name)
      if(local != null){
          return JSON.parse(local)
      }
      return null
   }
  const setLocalStorage = item => {
     localStorage.setItem(name, JSON.stringify(item))
  }
  const removeLocalStorage = () => {
      return localStorage.removeItem(name)
  }
  return [getLocalStorage, setLocalStorage, removeLocalStorage]
}

Hook cung cấp 3 dịch vụ:

  • getLocalStorage: Dùng để truy xuất dữ liệu trong localstorage
  • setLocalStorage: Lưu dữ liệu vào localstorage
  • removeLocalStorage: Đơn giản là xóa dữ liệu trong localstorage

Cả 3 dịch vụ này đều sử dụng name là key mỗi khi tương tác với localstorage. Thông thường thì giá trị name này sẽ được gán với mỗi input.

Cách sử dụng Custom Hook

Sau khi đã định nghĩa xong custom hook, giờ là lúc chúng ta mang ra sử dụng thôi.

👏 Nếu bạn chưa biết React Hook là gì thì đọc lại nhé: Hooks là gì – Điều gì khiến React Hook hấp dẫn?

Quay trở lại App.js, chúng ta sẽ sửa lại một chút:

export default function App() {
  let initialForm = {
    name: "",
    website: "",
    phone: ""
  }
  const [savedForm, setSavedForm, clearLocalStorage] = useLocalStorage("inputForm");
  const [inputFormState, setInputFormState] = useState(savedForm() || initialForm);

  const handleFormChange = (event) => {
    const {name, value} = event.target;
    setInputFormState((prev) => {
      const newForm = {...prev}
      newForm[name] = value
      return newForm
    })
  };
  
  useEffect(() => {
    setSavedForm(inputFormState)
  },[setSavedForm, inputFormState]);

  
  return (
    <div className="App">
      <div className="title">Bản đăng ký thông tin</div>
      <div className="sub-title">@vntalking.com</div>
      <hr></hr>
      <div className="row">
        <div className="label">Họ tên:</div>
        <input className="input" name="name" value={inputFormState?.name} onChange={(e) => handleFormChange(e)}/>
      </div>
      <div className="row">
        <div className="label">Website:</div>
        <input className="input" name="website" value={inputFormState?.website} onChange={(e) => handleFormChange(e)}/>
      </div>
      <div className="row">
        <div className="label">Điện thoại:</div>
        <input className="input" name="phone" value={inputFormState?.phone} onChange={(e) => handleFormChange(e)}/>
      </div>
      <div><button onClick={()=>clearLocalStorage()}>Xóa Cache</button></div>
    </div>
  );
}

Kết quả thu được như sau:

Persisting State React JSVới custom hook ở trên, bạn có thể làm được nhiều thứ hơn, ví dụ như mã hóa dữ liệu trước khi lưu vào storage để đảm bảo an toàn.v.v…

Minh hi vọng, đây là một giải pháp Persisting State React JS hiệu quả để lưu dữ liệu và phù hợp với dự án của bạn.

Ý kiến của bạn thế nào? Đừng ngần ngại để lại bình luận góp ý bên dưới nhé.

Tải mã nguồn minh họa tại đây:

💥 Đọc thêm về React JS:

Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng
Bài trướcPure Function là gì? Tại sao phải là Pure function chứ
Bài tiếp theoAR là gì? Cách phát triển ứng dụng AR trên Android
Sơn Dương
Tên đầy đủ là Dương Anh Sơn. Tốt nghiệp ĐH Bách Khoa Hà Nội. Mình bắt đầu nghiệp coder khi mà ra trường chẳng xin được việc đúng chuyên ngành. Mình tin rằng chỉ có chia sẻ kiến thức mới là cách học tập nhanh nhất. Các bạn góp ý bài viết của mình bằng cách comment bên dưới nhé !

Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Thông báo