Implementing Auto-Save in React with Custom Hooks

optimization

Auto-save is a crucial feature for enhancing user experience by saving user input automatically. It can be useful in the case of Forms, text editors, draft-saving, etc.

We'll create a custom useAutosave hook that leverages useEffect and useRef hooks for debouncing save operations.

Debouncing is a technique in programming that helps prevent time-consuming tasks from being triggered so frequently that they slow down the performance of an application.

import React from "react";

function useAutosave(callback, delay = 1000, deps = []) {
  const savedCallback = React.useRef(callback);
  // callback ref update
  React.useEffect(() => {
    savedCallback.current = callback;
  }, [callback]);

  React.useEffect(() => {
    // creating debounce effect to optimise API calls
    const handler = setTimeout(() => {
      savedCallback.current();
    }, delay);

    // Clean up the timeout if any dependency changes
    return () => clearTimeout(handler);
  }, deps); // Only reset the timeout when dependencies change
}

export default useAutosave;

Using the useAutosave Hook in a Component

import React, { useState } from "react";
import useAutosave from "./useAutosave";

const AutoSaveForm = () => {
  const [formData, setFormData] = useState({ name: "", email: "" });
  const [isSaving, setIsSaving] = useState(false);

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({ ...formData, [name]: value });
  };

  const handleAutoSave = async () => {
    setIsSaving(true);
    // Simulating an API call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    console.log("Auto-saved data:", formData);
    setIsSaving(false);
  };

  /* handleAutoSave will be called after 5 seconds if there's 
    any change in the formData */
  useAutosave(handleAutoSave, 5000, [formData]);

  return (
    <div>
      <form>
        <div>
          <label>Name:</label>
          <input type="text" name="name" value={formData.name} onChange={handleChange} />
        </div>
        <div>
          <label>Email:</label>
          <input type="email" name="email" value={formData.email} onChange={handleChange} />
        </div>
      </form>
      {isSaving && <p>Saving...</p>}
    </div>
  );
};

export default AutoSaveForm;

Note: Consider adding error handling, customizing debounce delays, or using external libraries for more complex scenarios.

Conclusion

I've demonstrated how to implement an auto-save feature using custom hooks in React. This method optimizes performance and enhances the user experience. Give it a try in your projects and let me know your feedback!