JavaScript >> Javascript 文檔 >  >> JavaScript

如何在 JavaScript 中使用本地存儲來持久化表單數據

如何利用本地存儲為用戶備份和恢復表單數據,提升用戶體驗。

開始使用

對於本教程,我們將使用 CheatCode Next.js 樣板作為我們工作的起點。首先,讓我們克隆一個副本:

終端

git clone https://github.com/cheatcode/nextjs-boilerplate.git

接下來,cd 進入項目並安裝依賴項:

終端

cd nextjs-boilerplate && npm install

最後,啟動開發服務器:

終端

npm run dev

有了這個,我們就可以開始了。

構建表單

在我們開始持久化表單數據之前,我們需要一個可以從中提取數據並將其加載回的表單。首先,我們將通過 React 添加一個新的頁面組件來容納我們的表單:

/pages/index.js

import React from "react";
import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {};

  render() {
    return (
      <StyledIndex>
        <form>
          // We'll render our form fields here...
        </form>
      </StyledIndex>
    );
  }
}

export default Index;

在 Next.js 應用程序中,/pages 下的所有文件和文件夾 文件夾在瀏覽器中兼作路由或 URL。在這裡,通過在 /pages/index.js 創建我們的頁面 ,在瀏覽器中,我們可以期望在 http://localhost:5000/ 處訪問我們的頁面 (我們應用程序的索引或根)。

對於我們的組件,我們在 React 中使用基於類的方法,而不是基於函數的方法(稍後在將數據從本地存儲加載到我們的表單中時,我們會從中受益)。在這裡,在 render() 裡面 方法,我們正在渲染一個樣式化的組件 <StyledIndex /> 我們將使用它來為我們的 <form></form> 應用一些基本樣式 .現在讓我們看一下那個文件:

/pages/index.css.js

import styled from "styled-components";

export default styled.div`
  form {
    max-width: 50%;
  }
`;

styled-components 是一個幫助輕鬆地將 CSS 添加到我們的 React 組件的庫。它的工作原理是自動生成包含一些 HTML 元素的 React 組件,然後將我們提供的樣式(這裡是反引號之間的內容)附加到該元素。上面,我們導入 styled 來自styled-components 包(自動安裝在我們之前克隆的樣板中),然後創建一個包含 HTML <div></div> 的新樣式組件 元素。

雖然它可能看起來不像,但這裡是 styled.div 技術上是一個函數 styled.div() .這裡的語法是 JavaScript 中的一個便利功能,它允許我們通過刪除括號並在傳遞的字符串周圍使用反引號來調用只期望字符串類型中的單個參數的函數。這裡的字符串包含我們的 CSS,它將表單的寬度限制為頁面的 50%。

/pages/index.js

import React from "react";
import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {};

  render() {
    return (
      <StyledIndex>
        <form>
          // We'll render our form fields here...
        </form>
      </StyledIndex>
    );
  }
}

export default Index;

回到我們的組件中,我們導入並渲染我們的樣式化組件,在本例中將它包裹在 HTML <form></form> 我們將在其中呈現表單字段的標籤。

/pages/index.js

import React from "react";
import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {};

  render() {
    return (
      <StyledIndex>
        <form>
          <div className="row">
            <div className="col-sm-6">
              <div className="mb-3">
                <label className="form-label">First Name</label>
                <input
                  type="text"
                  name="firstName"
                  className="form-control"
                />
              </div>
            </div>
            <div className="col-sm-6">
              <div className="mb-3">
                <label className="form-label">Last Name</label>
                <input
                  type="text"
                  name="lastName"
                  className="form-control"
                />
              </div>
            </div>
          </div>
          <div className="row">
            <div className="col-sm-12">
              <div className="mb-3">
                <label className="form-label">Favorite Ice Cream Flavor</label>
                <select
                  className="form-select"
                >
                  <option value="chocolate">Chocolate</option>
                  <option value="vanilla">Vanilla</option>
                  <option value="strawberry">Strawberry</option>
                  <option value="neopolitan">Neopolitan</option>
                </select>
              </div>
            </div>
          </div>
          <div className="row">
            <div className="col-sm-12">
              <div className="mb-5">
                <label className="form-label">Toppings</label>
                <div class="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="sprinkles"
                  />
                  <label className="form-check-label">Sprinkles</label>
                </div>
                <div className="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="cherry"
                  />
                  <label className="form-check-label">Cherry</label>
                </div>
                <div className="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="hotFudge"
                  />
                  <label className="form-check-label">Hot Fudge</label>
                </div>
              </div>
            </div>
          </div>
          <button className="btn btn-primary" style={{ marginRight: "10px" }}>
            Submit
          </button>
          <button
            className="btn btn-light"
            type="button"
          >
            Reset Form
          </button>
        </form>
      </StyledIndex>
    );
  }
}

export default Index;

填寫表單的主體,在這裡,我們添加了混合的 HTML 輸入來演示從表單中檢索數據,然後在從本地存儲刷新頁面後將其設置回來。我們有六個字段:

  1. 名字文本輸入
  2. 姓氏文本輸入
  3. 用於選擇您最喜歡的冰淇淋口味的選擇輸入
  4. 用於檢查冰淇淋配料的一系列複選框

雖然我們的表單將呈現在屏幕上並且可以填寫,但如果我們刷新頁面,我們輸入到表單中的任何數據都將丟失。接下來,為了避免這種情況,我們將學習如何首先將數據存儲在 React 組件的狀態中,然後將其備份到本地存儲。

設置狀態和本地存儲數據

上面,我們設置了一個頁面組件來呈現我們的表單字段。現在,我們想從該表單中的輸入中獲取值,並將它們設置在我們組件的狀態以及本地存儲中。為此,我們將添加一個可以從所有輸入中調用的函數,該函數將集中設置狀態 上的輸入值 本地存儲。

終端

import React from "react";
import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {};

  handleUpdateState = (field = "", value = "") => {
    this.setState({ [field]: value }, () => {
      if (localStorage) {
        localStorage.setItem("formData", JSON.stringify(this.state));
      }
    });
  };

  render() {
    const { firstName, lastName, iceCreamFlavor, sprinkles, cherry, hotFudge } =
      this.state;

    return (
      <StyledIndex>
        <form>
          <div className="row">
            <div className="col-sm-6">
              <div className="mb-3">
                <label className="form-label">First Name</label>
                <input
                  type="text"
                  name="firstName"
                  value={firstName}
                  onChange={(event) =>
                    this.handleUpdateState("firstName", event.target.value)
                  }
                  className="form-control"
                />
              </div>
            </div>
            <div className="col-sm-6">
              <div className="mb-3">
                <label className="form-label">Last Name</label>
                <input
                  type="text"
                  name="lastName"
                  value={lastName}
                  onChange={(event) =>
                    this.handleUpdateState("lastName", event.target.value)
                  }
                  className="form-control"
                />
              </div>
            </div>
          </div>
          <div className="row">
            <div className="col-sm-12">
              <div className="mb-3">
                <label className="form-label">Favorite Ice Cream Flavor</label>
                <select
                  className="form-select"
                  value={iceCreamFlavor}
                  onChange={(event) =>
                    this.handleUpdateState("iceCreamFlavor", event.target.value)
                  }
                >
                  <option value="chocolate">Chocolate</option>
                  <option value="vanilla">Vanilla</option>
                  <option value="strawberry">Strawberry</option>
                  <option value="neopolitan">Neopolitan</option>
                </select>
              </div>
            </div>
          </div>
          <div className="row">
            <div className="col-sm-12">
              <div className="mb-5">
                <label className="form-label">Toppings</label>
                <div class="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="sprinkles"
                    checked={sprinkles}
                    onChange={(event) =>
                      this.handleUpdateState("sprinkles", event.target.checked)
                    }
                  />
                  <label className="form-check-label">Sprinkles</label>
                </div>
                <div className="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="cherry"
                    checked={cherry}
                    onChange={(event) =>
                      this.handleUpdateState("cherry", event.target.checked)
                    }
                  />
                  <label className="form-check-label">Cherry</label>
                </div>
                <div className="form-check">
                  <input
                    className="form-check-input"
                    type="checkbox"
                    value="hotFudge"
                    checked={hotFudge}
                    onChange={(event) =>
                      this.handleUpdateState("hotFudge", event.target.checked)
                    }
                  />
                  <label className="form-check-label">Hot Fudge</label>
                </div>
              </div>
            </div>
          </div>
          <button className="btn btn-primary" style={{ marginRight: "10px" }}>
            Submit
          </button>
          <button
            className="btn btn-light"
            type="button"
          >
            Reset Form
          </button>
        </form>
      </StyledIndex>
    );
  }
}

export default Index;

在這裡,我們在類 handleUpdateState 中添加了一個函數 它接受兩個參數:fieldvalue .第一個參數 field 是我們要在 state 和 value 上設置的字段的名稱 是我們要分配給該字段的值。

在該函數內部,我們調用 this.setState() 更新我們組件的狀態值,使用一種特殊的括號符號語法來幫助我們動態地設置我們想要更新的狀態屬性(在狀態上設置值時,我們在對像上傳遞一個或多個鍵/值對)。這裡,[field] 將被替換為任何 field 我們作為第一個參數傳入的字符串,例如 { firstName: value }{ iceCreamFlavor: value } .

稍後我們會看到,這允許我們調用 handleUpdateState 從任何表單字段,同時確保我們的行為是一致的。同樣在這個函數內部,我們將一個回調函數傳遞給 this.setState() 告訴 React “在你成功地將我們的字段的值提交給組件的狀態之後執行此操作。”在那個函數中,我們介紹了我們對本地存儲的使用。

首先,我們做一個 if (localStorage) 以確保本地存儲可用。這是必要的,因為某些瀏覽器可能不支持本地存儲。 這包括在私有模式下運行的現代瀏覽器 .

如果 localStorage 存在,我們調用它的.setItem 方法,首先將我們要存儲的值的名稱作為第一個參數傳遞,然後將我們要存儲的值作為第二個參數傳遞。在這裡,因為 localStorage 只支持字符串存儲,我們使用JSON.stringify 將我們的整個 this.state 字符串化 價值。我們這樣做是因為我們想要 localStorage 成為用戶輸入的最新表示。

在我們的 render() 中 方法,我們添加了兩件事:

  1. 我們使用 JavaScript 解構從 this.state 中“提取”我們的輸入值 並將每個值分配給 value 我們每個輸入的屬性(這會在 React 中創建所謂的受控組件)。
  2. 對於每個輸入,我們添加了一個 onChange 接受 DOM event 的函數 並調用 this.handleUpdateState() ,傳遞字段的名稱及其值。對於 <input type="checkbox" /> 元素,而不是傳遞 event.target.value 我們通過 event.target.checked .

現在,如果我們開始輸入表單,我們應該會看到我們的 formData 瀏覽器本地存儲中的值更新:

我們快完成了。為了總結並使其有用,接下來,我們將學習如何在頁面刷新後將我們放入本地存儲的數據加載回我們的表單。

從本地存儲恢復表單

這就是我們使用基於類的 React 組件方法獲得回報的地方。為了將數據加載回我們的表單,我們需要知道表單存在於 DOM 中。為此,我們可以使用 componentDidMount() React 中的生命週期函數,讓我們知道我們的表單在屏幕上並準備好接收我們的數據。

/pages/index.js

import React from "react";
import StyledIndex from "./index.css";

class Index extends React.Component {
  state = {};

  componentDidMount() {
    if (localStorage) {
      const formDataFromLocalStorage = localStorage.getItem("formData");
      if (formDataFromLocalStorage) {
        const formData = JSON.parse(formDataFromLocalStorage);
        this.setState({ ...formData });
      }
    }
  }

  handleUpdateState = (field = "", value = "") => { ... };

  render() {
    const { firstName, lastName, iceCreamFlavor, sprinkles, cherry, hotFudge } =
      this.state;

    return (
      <StyledIndex>
        <form>
          ...
        </form>
      </StyledIndex>
    );
  }
}

export default Index;

componentDidMount() 內部 ,我們首先檢查是否有localStorage 已定義,如果已定義,請嘗試檢索我們的 formData localStorage 中的值 使用 .getItem() 方法,傳入我們的值的名稱 formData 作為一個字符串。

接下來,如果我們得到一個值,我們需要將我們存儲的字符串轉換回 JavaScript 對象。為此,我們通過 formDataFromLocalStorageJSON.parse() .接下來,使用我們的 formData 作為一個對象,我們調用 this.setState() , 傳遞一個使用 JavaScript ... 設置屬性的對象 展開運算符以“解包”formData 上的所有屬性 到我們傳遞給 .setState() 的對像上 (這使得每個單獨的屬性都被設置回狀態)。

有了它,我們就可以填寫表單,刷新頁面,然後查看我們的值是否被持久化了!

總結

在本教程中,我們學習瞭如何在 React 中構建一個表單,將其內容存儲在組件的 this.state 中 值並將該值支持到 localStorage .我們學習瞭如何有條件地訪問 localStorage 避免不支持的瀏覽器出現問題以及如何從 localStorage 檢索現有值 並將其應用回 this.state 當組件掛載時。


Tutorial JavaScript 教程
  1. 從 switch 語句中返回是否被認為是比使用 break 更好的做法?

  2. 有用的類型:使用 TypeScript 提取路由參數

  3. 為什麼我們為 Hasura 控制台選擇 Typescript

  4. 在我的智能手機上使用 mysql 運行節點服務器

  5. 您從未聽說過的 JavaScript API(有些您已經聽說過)

  6. 教程:Node.js 和 MongoDB JSON REST API 服務器與 Mongoskin 和 Express.js

  7. 放大和反應:創建應用程序

  1. 我如何計算 Java Script 數組中的項目,但僅當項目彼此相鄰時?

  2. 如何查找未顯示的元素的高度

  3. 重新思考 Vue 全棧

  4. 🚀 [GIF] Javascript Promise API 方法的備忘單 - Promise.all、Promise.allSettled、Promise.race、Promise.any

  5. 使用 PayPal 結帳 React 開源電子商務 Web 應用程序

  6. TypeScript 曾經在我的 $#!% 💩 列表中

  7. jQuery的JSONP用例子解釋

  1. 如何在 Contentful 中使用 YouTube 🏄

  2. 使用 Next.js 和 Vercel 設置 Supabase

  3. 在 Prisma 中管理遷移(添加/重命名列)

  4. 如何在 Node.js 中使用流