React:为什么本地存储中的变量在短暂达到所需值后会重置为未定义?

问题描述 投票:0回答:3

我是 React 新手,正在编写一些玩具代码,其期望的行为是允许用户在表单中输入他们的姓名,并且提交后页面将显示“Hello {user's name}”。

但是,观察到的行为是页面短暂闪烁以呈现“Hello {用户的姓名}”,然后返回到默认呈现,就好像没有提交姓名一样。

我当前的方法是在使用

useEffect
提交时将用户名保存在本地存储中。但是,从观察控制台日志来看,本地存储似乎在将
name
变量设置为输入的名称后立即将其重置为
undefined

下面是代码:

function NameForm() {
  const [name, setName] = useState(window.localStorage.getItem("name") || "");
  useEffect(() => {
    setName(window.localStorage.setItem("name", name));
    console.log(name);
  }, [name]);
  return (
    <>
      <form
        onSubmit={event => {
          event.preventDefault();
          setName(event.target.elements.usernameInput.value);
          return false;
        }}
      >
        <label>Enter your name</label>
        <input id="usernameInput" />
        <button type="submit"> Submit</button>
      </form>
      <h1>Hello {name}</h1>
    </>
  );
}
export default function App() {
  return (
    <div className="App">
      <NameForm />
    </div>
  );
}

这里也是用来运行代码的codesandbox。

为什么会发生这种意外行为以及如何解决它?

reactjs local-storage
3个回答
1
投票

为什么会有意想不到的行为

window.localStorage.setItem("name", name)
返回未定义。所以你本质上是在 useEffect 中做
setName(undefined)
。于是就有了这个问题。

如何解决? 您可以通过多种方式进行修复。一种方法是简单地摆脱 useEffect 并在

onSubmit
中执行 localStorage.setItem,然后立即执行 setName。

更新了代码和框链接

<>
      <form
        onSubmit={event => {
          event.preventDefault();
          window.localStorage.setItem(
            "name",
            event.target.elements.usernameInput.value
          );
          setName(event.target.elements.usernameInput.value);
        }}
      >
        <label>Enter your name</label>
        <input id="usernameInput" />
        <button type="submit"> Submit</button>
      </form>
      <h1>Hello {name}</h1>
    </>

您可以通过受控输入解决您的问题。


1
投票

你想要完成的事情需要用另一种方式来完成。用户提交名称时需要设置本地存储。之后您还可以调用

setName
来更新组件。您想要在 componentDidMount 中执行的操作是从本地存储中获取名称。我编辑您提供的沙箱。我还在下面留下一份副本。 沙盒

import React, { useState, useEffect } from "react";
import "./styles.css";

function NameForm() {
  const [name, setName] = useState(window.localStorage.getItem("name") || "");
  useEffect(() => {
    setName(window.localStorage.getItem("name"));
    console.log(name);
  }, [name]);

  return (
    <>
      <form
        onSubmit={event => {
          event.preventDefault();
          let new_name = event.target.elements.usernameInput.value;
          window.localStorage.setItem("name", new_name);
          setName(new_name);
          return false;
        }}
      >
        <label>Enter your name</label>
        <input id="usernameInput" />
        <button type="submit"> Submit</button>
      </form>
      <h1>Hello {name}</h1>
    </>
  );
}
export default function App() {
  return (
    <div className="App">
      <NameForm />
    </div>
  );
}

1
投票

您所需要做的只是在设置值之前应用一个条件。提交表单后,您的姓名值将变得不确定并被存储。 您现在会声明您已经使用了

useState(window.localStorage.getItem("name") || "")
那么它怎么可能是未定义的。 这是因为竞争条件。在 localStorage 中设置 Item 需要一些时间,并且在设置之前您的组件将被渲染。

您也可以直接使用

localStorage
而不是使用
window.localStorage
: 这是你需要做的

 useEffect(() => {
    if(name)
    setName(window.localStorage.setItem("name", name));
    console.log(name);
  }, [name]);

© www.soinside.com 2019 - 2024. All rights reserved.