如何从 localStorage 设置 React 状态?

Posted

技术标签:

【中文标题】如何从 localStorage 设置 React 状态?【英文标题】:How to set React state from localStorage? 【发布时间】:2018-04-03 00:49:45 【问题描述】:

我很难弄清楚如何使用 React 和 TS 从 localStorage 设置组件状态。在我检查 localStorage 实例是否存在后,它仍然说不兼容类型,因为localStorage.getItem() 仍然可以返回字符串或 null。

如果我更改界面并添加string | null,我可以从localStorage 设置状态,但是我不再能够自行设置localStorage,因为localStorage.setItem() 似乎只接受string 而不是string | null

编辑

我想出了这个问题的“解决方案”。我不确定这是否是不好的做法,但它似乎有效。如果这可以写得更好,请告诉我。

componentWillMount() 
    let from = localStorage.getItem('from');
    let to = localStorage.getItem('to');
    let fromId = localStorage.getItem('fromId');
    let toId = localStorage.getItem('toId');

    if (typeof from === 'string' &&
        typeof to === 'string' &&
        typeof fromId === 'string' &&
        typeof toId === 'string') 

      this.setState(
        inputFrom: from,
        inputTo: to,
        fromId: fromId,
        toId: toId,
      );
    
  

编译错误:

类型参数 ' inputFrom: string |空值; ' 不可分配给“Pick”类型的参数。 属性“inputFrom”的类型不兼容。 键入'字符串 | null' 不可分配给类型 'string'。 类型 'null' 不能分配给类型 'string'。

我的接口实现如下:

interface State 
  inputFrom: string,
  inputTo: string,
  fromId: string,
  toId: string,
  tripdata: ,
  loading: boolean,
  error: boolean,

我的组件

import * as React from 'react';
import Header from './components/Header';
import SearchForm from './components/search/SearchForm';
import API from './api/APIService';
import TripTable from './components/trips/TripTable';
import Loading from './components/atoms/Loading';
import Error from './components/atoms/Error';
import './App.css';
const api = new API;

interface State 
  inputFrom: string,
  inputTo: string,
  fromId: string,
  toId: string,
  tripdata: ,
  loading: boolean,
  error: boolean,


class App extends React.Component<any, State> 
  constructor() 
    super();
    this.state = 
      inputFrom: '',
      inputTo: '',
      fromId: '',
      toId: '',
      tripdata: ,
      loading: false,
      error: false,
    ;
  

  componentWillMount() 
    let from = localStorage.getItem('from');
    if (from !== null || from !== undefined) 
      this.setState(
        inputFrom: from,
      );
    
  

  handleSubmit = () => 
      if (this.state.fromId !== '' && this.state.toId !== '') 
        this.setState(error: false);
        this.setState(loading: true);
        api.GetAccessToken()
        .then((token: string) => 
          api.GetTripFromSearch(token, this.state.fromId, this.state.toId)
        .then((res) => 
          this.setState(
            tripdata: res,
            loading: false,
          );
        );
          localStorage.setItem('from', this.state.inputFrom);
          localStorage.setItem('to', this.state.inputTo);
          localStorage.setItem('fromId', this.state.fromId);
          localStorage.setItem('toId', this.state.toId);
      );
     else 
      this.setState(error: true);
    
  

  render() 
    let triptable: JSX.Element | null;
    let loading: JSX.Element | null;
    let error: JSX.Element | null;

    if (this.state.tripdata !== null) 
      triptable = <TripTable tripdata=this.state.tripdata />;
     else 
      triptable = null;
    
    if (this.state.loading) 
      loading = <Loading />;
      triptable = null;
     else 
      loading = null;
    
    if (this.state.error) 
      error =  <Error />;
     else 
      error = null;
    
    return (
        <div>
          <Header />  
          <SearchForm 
            resetInputId=this.resetInputId
            handleInputFrom=this.handleInputFrom
            handleInputTo=this.handleInputTo
            handleSubmit=this.handleSubmit
            error=error
            handleSwap=this.handleSwap
          />
          loading
          triptable
        </div>        
    );
  



export default App;

【问题讨论】:

我在您的代码中看不到任何Pick 类型,它来自哪里?你的代码在这篇文章中是最新的吗? 感谢您的回复。代码是最新的。确实很奇怪。我的代码中没有 Pick 之类的东西。但是我想我找到了解决问题的方法。也许丑陋,但它现在有效。 我认为你也可以在handleSubmit 中进行类型检查,但我不确定 这能回答你的问题吗? Argument of type 'string | null' is not assignable to parameter of type 'string'. Type 'null' is not assignable to type 'string' 您所要做的就是告诉编译器该值不为空。 【参考方案1】:

在我的具体情况下,我试图从本地存储中获取布尔值。本地存储不保存布尔值。所以如果你给它'true',它会将它保存为一个字符串。这就是 if 的用途。实际上,您可以使这个看起来更漂亮,但为了清楚起见,我在这里使用了 else if。

在这种情况下,我将 checkLocalStorage 函数放置在组件之外。我不明白为什么它在组件内部不起作用,但 this 帖子告诉我将它放在组件外部,所以我就是这样做的。

ps:如果本地存储中没有任何内容,则为空。这是我用来设置默认值的。

const checkLocalStorage = () => 
  const ls = localStorage.getItem('item')
  if (ls === null || ls === 'true') 
    return true
   else if (ls === 'false') 
    return false
  


export const MyComponent = () => 

  const [state, setState] = useState(checkLocalStorage())

// rest of your code here

【讨论】:

错字:第三行应该是if (ls === null || ls === 'true') @edemaine 正确。我庆祝得太早了,没有彻底测试它,哈哈。谢谢你的纠正。实际上有没有一种方法可以做到这一点而不必输入 ls === 两次?因为我找不到。 不,这是最好的方法。您可以使用[null, 'true'].indexOf(ls) &gt;= 0,但这可能会慢一些。或者,您可以重组为 if (ls === 'false') return false else return true,它的行为略有不同(但更多的是布尔值)。 @edemaine Huh,老实说看起来很干净。我应该偷那个。

以上是关于如何从 localStorage 设置 React 状态?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 react.js 中收听 localstorage

如何在reducer中处理异步promise

React JS:从 localStorage 中删除一个项目

Svelte/Sapper.js - 如何使用 localStorage 数据初始化存储?

如何在React库的LocalStorage中存储令牌

使用 useState 和 useContext React Hooks 持久化 localStorage