React和localStorage获得NaN

时间:2016-11-29 14:59:57

标签: javascript reactjs local-storage

我之前从未真正使用过localStorage,但这似乎很容易。唉,我遇到了一些与React一起使用它的奇怪问题。

我试图保存localStorage中项目的点击次数,因此当我浏览应用程序时会保存数据。

我在控制台中查看localStorage,而setItem可以按照预期的方式点击和增加点击,但有几件事情正在发生

  1. 在第一次点击时,点击次数正在从DOM中消失。
  2. 首次点击后,该值将变为NaN
  3. 当我导航到另一个页面并使用浏览器导航返回该页面时。信息消失了。我猜这有什么可做的事情与React钩子我没有正确使用,但我可能是错的。
  4. 这是代码。

    import React, { Component } from 'react';
    import {IndexLink} from 'react-router';
    /* eslint-disable */
    import Item from '../styles/LinkItem.css';
    
    class LinkItem extends Component {
      constructor(props) {
        super(props);
        this.state = {
          clicks: 0,
          text: this.props.link,
          newText: null
        };
      }
      getClicksCount() {
        const localStorageRef = localStorage.getItem('link-' + this.props.link);
    
        if(localStorageRef) {
          this.setState({
            clicks: JSON.parse(localStorageRef) + 1
          })
        }
      }
      componentWillMount() {
        this.getClicksCount()
      }
      editLink() {
        const newText = prompt('Update your link');
        this.setState({
          newText: newText
        }, function(){
          this.props.data.updateLink(this.props.index, this.state.newText);
        })
      }
      handleClick(e) {
        e.preventDefault();
        const clicks = this.state.clicks;
        this.getClicksCount();
      }
      render() {
          return (
            <tr>
              <td>
                  <IndexLink onClick={this.handleClick.bind(this)} to={{pathname: 'landing/' + this.props.link}}>{this.state.newText != null ? this.state.newText : this.props.link}</IndexLink>
              </td>
              <td>{this.state.clicks}</td>
              <td><button className="btn btn-default" onClick={this.editLink.bind(this)}>Edit</button></td>
              <td><button className="btn btn-danger" onClick={this.props.data.deleteLink.bind(null, this.props.index)}>Delete</button></td>
            </tr>
        );
      }
    }
    
    export default LinkItem;
    

1 个答案:

答案 0 :(得分:1)

问题在于:

this.setState({
  clicks: JSON.stringify(localStorage.setItem('link-' + this.props.link, clicks + 1))
});

localStorage.setItem返回undefined。所以你打破了你的状态,这就是为什么你有一个空的点击数字。

将方法componentWillMount重命名为getClicksCount,并在新的componentWillMount和方法handleClick的末尾调用它。因此,单一职责的方法更简单:handleClick只更新localStorage,getClicksCount只更新状态。

UPD:我写了一些方法和评论。我没有测试它,但我认为它会起作用。随意提问。

import React, { Component } from 'react';
import { IndexLink } from 'react-router';
/* eslint-disable */
import Item from '../styles/LinkItem.css';

class LinkItem extends Component {
  constructor(props) {
    super(props);
    this.state = {
      clicks: 0,
      text: this.props.link,
      newText: null
    };
  }
  // new methods:
  getStoreKey() {
    return 'link-' + this.props.link;
  }
  getClicksCount() {
    const key = this.getStoreKey();
    const value = localStorage.getItem(key);
    return JSON.parse(value);
  }
  setClicksCount(newValue) {
    const key = this.getStoreKey();
    localStorage.setItem(key, newValue);
  }
  updateClicksCountState(val) {
    this.setState({
      clicks: val,
    });
  }
  //
  componentWillMount() {
    this.updateClicksCountState(this.getClicksCount()); // that should update state with value from localStorage
  }
  editLink() {
    const newText = prompt('Update your link');
    this.setState({
      newText: newText
    }, function(){
      this.props.data.updateLink(this.props.index, this.state.newText);
    })
  }
  handleClick(e) {
    e.preventDefault();
    const oldValue = this.getClicksCount();
    const newValue = oldValue + 1;
    this.setClicksCount(newValue);         // that will update value in localStorage
    this.updateClicksCountState(newValue); // that will update state -> render component
  }
  render() {
      return (
        <tr>
          <td>
              <IndexLink onClick={this.handleClick.bind(this)} to={{pathname: 'landing/' + this.props.link}}>{this.state.newText != null ? this.state.newText : this.props.link}</IndexLink>
          </td>
          <td>{this.state.clicks}</td>
          <td><button className="btn btn-default" onClick={this.editLink.bind(this)}>Edit</button></td>
          <td><button className="btn btn-danger" onClick={this.props.data.deleteLink.bind(null, this.props.index)}>Delete</button></td>
        </tr>
    );
  }
}

export default LinkItem;