17370845950

解决React应用中从LocalStorage渲染数据的问题

本文旨在解决React应用中从LocalStorage加载数据时,数据无法在页面刷新或重新加载后正确渲染的问题。通过分析常见原因,并提供详细的代码示例,帮助开发者理解如何正确地在React组件中使用`useEffect`钩子和LocalStorage,以确保数据的持久化和正确渲染。

在React应用中,从LocalStorage读取数据并在组件中渲染是一个常见的需求。然而,开发者经常遇到页面刷新或重新加载后,LocalStorage中的数据无法正确渲染的问题。这通常是由于对useEffect钩子的不当使用以及LocalStorage的写入时机造成的。

问题分析

问题的核心在于,在组件初始化时,contacts状态变量被初始化为空数组 []。随后,useEffect钩子尝试将此空数组写入LocalStorage。这导致每次页面加载时,LocalStorage中的数据都被重置为空,从而导致渲染问题。

  const [contacts, setContacts] = useState([
    {
      id: Math.random().toString(36).substr(2, 9),
      fullName: "Vekjko Petrovic",
      address: "121 Town Commons Way Phoenix, AZ, 45215",
      phone: 123_465_689,
      date,
    },
    {
      id: Math.random().toString(36).substr(2, 9),
      fullName: "Marko Petrovic",
      address: "Srbina 35, 11300 Smederevo Srbija",
      phone: 256_269_866,
      date,
    },
    {
      id: Math.random().toString(36).substr(2, 9),
      fullName: "Michael Jackson",
      address: "52 City St, Detroit, Mi, 46218",
      phone: 359_525_555,
      date,
    },
    {
      id: Math.random().toString(36).substr(2, 9),
      fullName: "Vanessa Parady",
      address: "11 Beogradska Beograd, SRB, 11000",
      phone: 123_465_689,
      date,
    },
  ]);

  useEffect(() => {
    const savedContacts = JSON.parse(localStorage.getItem("contacts"));

    if (savedContacts) {
      setContacts(savedContacts);
    }
  }, []);

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

上述代码中,第一个useEffect尝试从LocalStorage加载数据,第二个useEffect则在每次contacts状态更新时将数据写入LocalStorage。问题在于,组件首次渲染时,contacts的初始值(即使有初始值)会立即触发第二个useEffect,覆盖LocalStorage中的数据。

解决方案

为了解决这个问题,需要调整LocalStorage的写入时机,避免在组件初始化时覆盖已有的数据。一个推荐的做法是将LocalStorage的写入操作放在添加或修改联系人的函数中。

以下是修改后的代码示例:

import React, { useState, useEffect } from "react";

export const Contacts = () => {
  const [contacts, setContacts] = useState([]);

  useEffect(() => {
    const savedContacts = localStorage.getItem("contacts");

    if (savedContacts) {
      setContacts(JSON.parse(savedContacts));
    }
  }, []);

  const addContact = (newContact) => {
    const newContactList = [...contacts, newContact];
    setContacts(newContactList);
    localStorage.setItem("contacts", JSON.stringify(newContactList));
  };

  return (
    
      
      {contacts.map((data, i) => (
        
      ))}
    
  );
};

const InputContact = ({addContact}) => {
    const [fullName, setFullName] = useState('');
    const handleSaveClick = () => {
        if (fullName.trim().length > 0) {
            addContact({ fullName, id: Math.random().toString(36).substr(2, 9) });
            setFullName('');
        }
    };

    return (
        
             setFullName(e.target.value)}
            />
            
        
    );
};

const Contact = ({data}) => {
    return (
        
            {data.fullName}
        
    );
};

在这个修改后的示例中,LocalStorage的写入操作被移动到了addContact函数中。只有在添加新联系人时,才会更新LocalStorage中的数据。

关键改进:

  1. 移除不必要的useEffect: 删除了在每次contacts状态更新时写入LocalStorage的useEffect。
  2. 在addContact函数中写入LocalStorage: 在添加新联系人后,立即更新LocalStorage,确保数据持久化。

总结

正确使用useEffect钩子和LocalStorage对于构建持久化的React应用至关重要。避免在组件初始化时覆盖LocalStorage中的数据,并将LocalStorage的写入操作放在适当的事件处理函数中,可以有效地解决数据渲染问题。

注意事项:

  • 确保在写入LocalStorage之前,将数据转换为JSON字符串 (JSON.stringify())。
  • 在从LocalStorage读取数据后,将其解析为JavaScript对象 (JSON.parse())。
  • 避免频繁地写入LocalStorage,因为这可能会影响性能。
  • 考虑使用更高级的状态管理方案(如Redux、Context API或MobX)来管理复杂应用的状态,尤其是在需要跨组件共享状态时。

通过遵循这些最佳实践,可以确保React应用能够正确地从LocalStorage加载和渲染数据,提供更好的用户体验。