React 前端导航

React 如何在页面刷新之后保持状态

经常在面试贴中看到这样一个问题:如何在页面刷新之后保持状态?

在React中,我们通常用useState来处理组件的状态,一旦页面刷新,组件卸载后再重新渲染,状态就会被重置,因为这种状态只保存内存中。但在有些场景下,我们希望在页面刷新之后,依然可以保存页面的状态。比如下面的代码示例:

import { useEffect, useState } from “react”;
export default function App() {
 const [count, setCount] = useState(0);
 
 const increaseCount = () => {
     return setCount(count + 1);
 }
 
 const decreaseCount = () => {
     return setCount(count — 1)
 }
 
 return (
     <div>
         <h1> Count {count} </h1>
         <button onClick={increaseCount}>+</button>
         <button onClick={decreaseCount}>-</button>
     </div>
 );
}

我们可以通过状态持久化的方案来决解这个问题,简单就说就是把状态缓存起来,需要用的时候再拿出来用,麻烦的是需要自己管理状态的缓存。

下面介绍几种常用的状态缓存的方式。

1. 浏览器缓存

我们熟知的比较常用的就是localStorage和sessionStorage这两个,具体用法这里就不介绍了,二者的主要区别在于生命周期,localStorage不删除不会消失,sessionStorage只在一个浏览器会话内有效,关闭浏览器tab自动删除。

为了使用方便,我们可以写个hook来使用,下面以locastorage为例:

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]
}

  • getLocalStorage:读取本地存储的状态
  • setLocalStorage:将状态存储到本地
  • removeLocalStorage:从本地存储中删除状态

使用示例:

import { useEffect, useState } from "react";
import { useLocalStorage } from "./utils/hooks";

let initialForm = {
  name: "",
  website: "",
  contact: {
    cell: "",
    email: "",
  },
};

const App = () => {
  const [savedForm, setSavedForm, clearLocalStorage] =
    useLocalStorage("inputForm");
  const [inputFormState, setInputFormState] = useState(
    savedForm() || initialForm
  );

  const handleFormChange = (event) => {
    const { name, value } = event.target;

    if (name === "name" || name === "website") {
      setInputFormState((prev) => {
        const newForm = { ...prev };
        newForm[name] = value;
        return newForm;
      });
    }

    if (name === "cell" || name === "email") {
      setInputFormState((prev) => {
        let newForm = { ...prev };
        newForm.contact[name] = value;
        return newForm;
      });
    }
  };

  useEffect(() => {
    setSavedForm(inputFormState);
  }, [setSavedForm, inputFormState]);

  return (
    <>
      <div>
        Name:
        <input
          name="name"
          value={inputFormState?.name}
          onChange={(e) => handleFormChange(e)}
        />
      </div>

      <div>
        Website:
        <input
          name="website"
          value={inputFormState?.website}
          onChange={(e) => handleFormChange(e)}
        />
      </div>
      <div>
        Cell:
        <input
          name="cell"
          value={inputFormState?.contact?.cell}
          onChange={(e) => handleFormChange(e)}
        />
      </div>
      <div>
        Email:
        <input
          name="email"
          value={inputFormState?.contact?.email}
          onChange={(e) => handleFormChange(e)}
        />
      </div>
      <div>
        <button onClick={() => clearLocalStorage()}>Clear Cache</button>
      </div>
    </>
  );
};

export default App;

sessionStorage同理。

2.history.state

histroy.state 可以保存我们的应用状态,与某一个访问记录绑定,页面跳转后就访问不到前一个页面的state,返回前一页面后可继续访问,需要使用 pushState 和 replaceState来修改history,用法及使用场景参考:history的pushState和replaceState用法及适用场景

3. URL

将状态保存到浏览器 URL 中,当我们初始化组件时,会从 URL 参数中读取初始值。

PS:由于 URL 长度限制,对于比较简单的数据此方法适用。

import { useEffect, useState } from "react";
import "./styles.css";
import qs from "qs";
import { createBrowserHistory } from "history";
export default function App() {
  const [count, setCount] = useState(0);
  const history = createBrowserHistory();
  useEffect(() => {
    const filterParams = history.location.search.substr(1);
    const filtersFromParams = qs.parse(filterParams);
    
    if (filtersFromParams.count) {
      setCount(Number(filtersFromParams.count));
    }
  }, []);
  useEffect(() => {
    history.push(`?count=${count}`);
  }, [count]);
  const increaseCount = () => {
    return setCount(count + 1);
  }
  const decreaseCount = () => {
    return setCount(count - 1)
  }
  return (
    <div className="App">
      <h1> Count {count} </h1>
      <button onClick={increaseCount}>+</button>
      <button onClick={decreaseCount}>-</button>
    </div>
  );
}

4. 其他库

下面列举一些可用的库,使用方法可自行搜索对应库文档,这里就不做赘述了。

  • @reduxjs/toolkit 结合 Redux-persist

  • recoil + recoil-persist

  • zustand(自带persist)

 

声明:本网站发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。邮箱:farmerlzj@163.com。 本站原创内容未经允许不得转载,或转载时需注明出处: 内容转载自: React前端网:https://qianduan.shop/blogs/detail/202

#react#状态管理

相关推荐

react中实现markdown文件读取展示

react中实现markdown文件读取展示

umi实践问题汇总--持续更新

在使用umi的过程中所遇到问题的记录汇总