簡體   English   中英

如何在 React.js 中刷新頁面后保持狀態?

[英]How to maintain state after a page refresh in React.js?

假設我有為上一頁選擇的選擇框設置狀態的代碼:

this.setState({selectedOption: 5});

有沒有辦法在頁面刷新后用 5 填充this.state.selectedOption

是否有回調可用於將其保存在 localStorage 中,然后執行一個大型setState或者是否有執行此類操作的標准方法?

所以我的解決方案是在設置狀態時也設置localStorage ,然后在getInitialState回調中再次從localStorage獲取值,如下所示:

getInitialState: function() {
    var selectedOption = localStorage.getItem( 'SelectedOption' ) || 1;

    return {
        selectedOption: selectedOption
    };
},

setSelectedOption: function( option ) {
    localStorage.setItem( 'SelectedOption', option );
    this.setState( { selectedOption: option } );
}

我不確定這是否可以被視為反模式,但除非有更好的解決方案,否則它可以工作。

您可以像 Omar Suggest 一樣使用本地存儲“持久化”狀態,但是一旦設置了狀態就應該這樣做。 為此,您需要將回調傳遞給setState函數,並且需要對放入本地存儲的對象進行序列化和反序列化。

constructor(props) {
  super(props);
  this.state = {
    allProjects: JSON.parse(localStorage.getItem('allProjects')) || []
  }
}


addProject = (newProject) => {
  ...

  this.setState({
    allProjects: this.state.allProjects.concat(newProject)
  },() => {
    localStorage.setItem('allProjects', JSON.stringify(this.state.allProjects))
  });
}

我們有一個應用程序,允許用戶在頁面中設置“參數”。 我們所做的是在 URL 上設置這些參數,使用 React Router(結合 History)和一個庫,該庫將 JavaScript 對象 URI 編碼為可用作查詢字符串的格式。

當用戶選擇一個選項時,我們可以將其值推送到當前路由上:

history.push({pathname: 'path/', search: '?' + Qs.stringify(params)});

pathname可以是當前路徑。 在你的情況下params看起來像:

{
  selectedOption: 5
}

然后,在作出反應樹的頂層,陣營路由器將更新props用的道具該組件的location.search這是我們之前設置的編碼值,所以會有一些在componentWillReceiveProps這樣的:

params = Qs.parse(nextProps.location.search.substring(1));
this.setState({selectedOption: params.selectedOption});

然后該組件及其子組件將使用更新的設置重新渲染。 由於信息位於 URL 上,因此可以將其添加為書簽(或通過電子郵件發送 - 這是我們的用例),刷新將使應用程序處於相同狀態。 這對我們的應用程序來說非常有效。

反應路由器: https : //github.com/reactjs/react-router

歷史: https : //github.com/ReactTraining/history

查詢字符串庫: https : //github.com/ljharb/qs

我認為狀態僅用於查看信息,並且應該在視圖狀態之外持續存在的數據最好存儲為道具。 當您希望能夠鏈接到一個頁面或在應用程序的深處共享 URL 但否則地址欄會變得混亂時,URL 參數很有用。

看看 Redux-Persist(如果您使用的是 redux) https://github.com/rt2zz/redux-persist

如果存在,則從 localStorage 加載狀態

constructor(props) {
    super(props);           
    this.state = JSON.parse(localStorage.getItem('state'))
        ? JSON.parse(localStorage.getItem('state'))
        : initialState

覆蓋this.setState以在每次更新后自動保存狀態

const orginial = this.setState;     
this.setState = function() {
    let arguments0 = arguments[0];
    let arguments1 = () => (arguments[1], localStorage.setItem('state', JSON.stringify(this.state)));
    orginial.bind(this)(arguments0, arguments1);
};

我可能會遲到,但是 react-create-app 的實際代碼用於 react > 16 ver。 每次更改后的狀態都保存在 sessionStorage(不是 localStorage)中並通過 crypto-js 進行加密。 刷新時(當用戶通過單擊刷新按鈕要求刷新頁面時)狀態從存儲中加載。 我還建議不要在構建中使用 sourceMaps 以避免關鍵短語的可讀性。

我的index.js

import React from "react";
import ReactDOM from "react-dom";
import './index.css';
import App from './containers/App';
import * as serviceWorker from './serviceWorker';
import {createStore} from "redux";
import {Provider} from "react-redux"
import {BrowserRouter} from "react-router-dom";
import rootReducer from "./reducers/rootReducer";
import CryptoJS from 'crypto-js';

const key = CryptoJS.enc.Utf8.parse("someRandomText_encryptionPhase");
const iv = CryptoJS.enc.Utf8.parse("someRandomIV");
const persistedState = loadFromSessionStorage();

let store = createStore(rootReducer, persistedState,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

function loadFromSessionStorage() {
    try {
        const serializedState = sessionStorage.getItem('state');
        if (serializedState === null) {
            return undefined;
        }
        const decrypted = CryptoJS.AES.decrypt(serializedState, key, {iv: iv}).toString(CryptoJS.enc.Utf8);
        return JSON.parse(decrypted);
    } catch {
        return undefined;
    }
}

function saveToSessionStorage(state) {
        try {
            const serializedState = JSON.stringify(state);
            const encrypted = CryptoJS.AES.encrypt(serializedState, key, {iv: iv});
            sessionStorage.setItem('state', encrypted)
        } catch (e) {
            console.log(e)
        }
}

ReactDOM.render(
    <BrowserRouter>
        <Provider store={store}>
            <App/>
        </Provider>
    </BrowserRouter>,
    document.getElementById('root')
);

store.subscribe(() => saveToSessionStorage(store.getState()));

serviceWorker.unregister();

使用鈎子和 sessionStorage:

const [count, setCount] = useState(1);

  useEffect(() => {
    setCount(JSON.parse(window.sessionStorage.getItem("count")));
  }, []);

  useEffect(() => {
    window.sessionStorage.setItem("count", count);
  }, [count]);

  return (
    <div className="App">
      <h1>Count: {count}</h1>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );

如果您仍然喜歡使用 localStorage 替換 sessionStorage。

嘗試將值存儲在本地存儲中,並在頁面加載時從本地存儲獲取值。 如果您還有其他值,則應使用redux進行數據存儲。

帶鈎子:

const MyComponent = () => {

  const [selectedOption, setSelectedOption] = useState(1)

  useEffect(() => {
    const storedSelectedOption = parseInt(sessionStorage.getItem('selectedOption') || '1')
    setSelectedOption(storedSelectedOption)
  }, [])

  const handleOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    setSelectedOption(parseInt(e.target.value))
    sessionStorage.setItem('selectedOption', e.target.value)
  }

  return (
    <select onChange={handleOnChange}>
      <option value="5" selected={selectedOption === 5}>Five</option>
      <option value="3" selected={selectedOption === 3}>Three</option>
    </select>
  )
}

顯然這也有效:

const MyComponent = () => {

  const [selectedOption, setSelectedOption] = useState<number>(() => {
    return parseInt(sessionStorage.getItem('selectedOption') || '1')
  })

  const handleOnChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    setSelectedOption(parseInt(e.target.value))
    sessionStorage.setItem('selectedOption', e.target.value)
  }

  return (
    <select onChange={handleOnChange}>
      <option value="5" selected={selectedOption === 5}>Five</option>
      <option value="3" selected={selectedOption === 3}>Three</option>
    </select>
  )
}

在現代瀏覽器中:

return (
  <select onChange={handleOnChange} value={selectedOption}>
    <option value="5">Five</option>
    <option value="3">Three</option>
  </select>
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM