如何将本地存储添加到我的React.js应用程序?

时间:2019-01-10 19:34:58

标签: javascript reactjs

我有一个应用-待办事项列表,其中包含存储列表项,评论,评论数等不同项目的评论。

您能帮我将localStorage添加到我的应用中,以便将所有项目保存到localStorage吗?

我读过一篇文章,说我们需要设置2个变量的路径:键和对象。我该如何传递所有物品的整个状态?

这是代码:

App.js

import React, { Component } from 'react';
import './App.css';
import ListInput from './components/listInput'
import ListItem from './components/listItem'
import SideBar from './components/sideBar'
import CommentsSection from './components/commentsSection'

class App extends Component {
  constructor(props){
    super(props);

    this.state = {
      items: [
        {
          id: 1, 
          title: 'First item',
          commentsCount: 0,
          comments: [],
          displayComment: false
        },
        {
          id: 2, 
          title: 'Second item',
          commentsCount: 0,
          comments: [],
          displayComment: false
        },
        {
          id: 3, 
          title: 'Third item',
          commentsCount: 0,
          comments: [],
          displayComment: false
        },
      ],
      activeItem: {},
      isHidden: true
    }
  }
  // Add new item to the list
  addItem = inputText => {
    let itemsCopy = this.state.items.slice();
    itemsCopy.push({id: this.state.items.length + 1, title: inputText, commentsCount: 0, comments: [], displayComment: false});

    this.setState({
      items: itemsCopy,
    })
  }
  // Remove the item from the list: check if the clicked button id is match 
  removeItem = id =>
    this.setState({
      items: this.state.items.filter((item, index) => item.id !== id)
    })

  addComment = (inputComment) => {
    // find item with id passed and select its comments array
     const commentCopy = this.state.items.map(item => {
       if (item.id === this.state.activeItem.id) {
         return {
           ...item, 
           commentsCount: item.comments.length + 1,
           comments: item.comments.concat({id: item.comments.length + 1, text: inputComment})
          } 
       }
         return item
      });
      this.setState({
       items: commentCopy
     })
   }

  getActiveItem = () => this.state.items.find(item => item.id === this.state.activeItem.id)

  render() {
    console.log(this.state.items.isHidden)
    return (
      <div className='App'>
        <SideBar />
        <div className='flex-container'>
          <div className='list-wrapper'>
            <h1>Items</h1>
            <ListInput inputText='' addItem={this.addItem}/>
            <ul>
              {
                this.state.items.map((item) => 
                (<ListItem 
                    item={item} 
                    key={item.id} 
                    id={item.id} 
                    removeItem={this.removeItem} 
                    setActiveComment={() => this.setState({ activeItem: item })} 
                    toggleHidden={() => this.setState({ isHidden: false })}
                  />
                ))
              }
            </ul>
          </div>
          <div>
            {!this.state.isHidden && <CommentsSection 
              addComment={this.addComment} 
              activeItem={this.getActiveItem()}
            />}
          </div>  
        </div>  
      </div>
    );
  }
}
export default App;

commentSection.js

import React from 'react';
import CommentInput from './commentInput'
import CommentsItem from './commentsItem'
import './commentsSection.css';

export default class CommentsSection extends React.Component {
    constructor(props){
        super(props);
        this.state = {value: ''};
    }

    handleChange = event => this.setState({value: event.target.value})

    handleEnter = event => {
        if (event.charCode === 13 && event.ctrlKey) {
            console.log(this.state, this.props)
            this.addComment(this.state.value)
        } 
    }    

    addComment = comment => {
        console.log(this.props.activeComment)
         // Ensure the comment text isn't empty
        if (comment.length > 0) {
          this.props.addComment(comment);
          this.setState({value: ''});
        }   
    }

    render() {
        return (
            <div className='component-section'>
                <h1>{this.props.activeItem && this.props.activeItem.title}</h1>
                <ul>
                { this.props.activeItem &&
                    this.props.activeItem.comments.map((comment) => <p key={comment.id}>{comment.text}</p>)
                }
                </ul>
                {/*<CommentsItem />*/}
                {/*<CommentInput addComment={this.addComment}/>*/}
                <div className='comment-input'>
                    <input type='text' value={this.state.value} onChange={this.handleChange} onKeyPress={this.handleEnter}/>
                </div>
            </div>
        )
    }
}

listInput.js

import React from 'react';
import './listInput.css'

export default class ListInput extends React.Component {
    constructor(props){
        super(props);
        this.state = {value: this.props.inputText};

        this.handleChange = this.handleChange.bind(this);
        this.addItem = this.addItem.bind(this);
    }

    handleChange = event => this.setState({value: event.target.value})

    addItem(item) {
        // Ensure the todo text isn't empty
        if (item.length > 0) {
          this.props.addItem(item);
          this.setState({value: ''});
        }   
    }

    render() {
      return (
        <div className='list-input'>
            <input type='text' value={this.state.value} onChange={this.handleChange} placeholder={'Type name here...'}/>
            <button className='btn btn-primary' onClick={() => this.addItem(this.state.value)}>Add new</button>
        </div>
      )
    }
  }

2 个答案:

答案 0 :(得分:1)

反应非常容易。

// setter
localStorage.setItem('myData', data);

// getter
localStorage.getItem('myData');

您可以通过浏览器自动访问localStorage对象。请记住,.setItem没有返回值,因此请同步使用它。

答案 1 :(得分:1)

简单说明:

localStorage有两种重要方法:

  • localStorage.setItem(*name*,*string value*)

    • 参数name只是您希望存储在Storage中以轻松引用数据的键。
    • 参数string value只是您希望存储在key/name下的“存储”中的值。重要的是它必须是一个字符串。 localStorage 无法存储数组和/或对象
  • localStorage.getItem(*name*)

    • 唯一必要的参数是name,它是先前为name设置的setItem
    • 如果key/name中不存在localStorage,则返回;如果存在 ,则返回字符串值

为什么这些事情很重要?状态是一个对象。让我们创建一个小版本:

let state = { name: "zak" };

如前所述,您不能localStorage中存储除 string 以外的任何内容。那我们该怎么办呢?我们要存储状态,对不对?嗯...我们必须将对象转换为一个字符串

我们可以使用JSON方法来做到这一点:

  • JSON.stringify(**object or array**)

    • 这将简单地接收任何传入的对象或数组,并将其转换为字符串
  • JSON.parse(**string**)

    • 这将使用任何字符串,并尝试使用JavaScript重新评估它以将其转换回 Object Array

我们有一个状态 Object ,我们需要将其转换为 string ,然后才能使用localStorage.setItem保存它。为此,我们使用JSON.stringify

使用localStorage.getItem时,我们将以字符串的形式接收状态对象的表示,我们需要先将其转换为状态 object 在我们的应用程序中使用它。为此,我们使用JSON.parse


保存的代码示例:

let state = { name: "zak" };

let state_string = JSON.stringify(state); 

localStorage.setItem("my_saved_state", state_string);

以上内容将处于状态,将其转换为字符串并保存。要进行相反的操作,我们只需获取字符串,然后将其变回对象


LOADING的代码示例:

let state = { name: "zak" };

let state_string = JSON.stringify(state); 

localStorage.setItem("my_saved_state", state_string);

let returned_state_string = localStorage.getItem("my_saved_state");

let returned_state_object = JSON.parse(returned_state_string);

以上结果为:

console.log(returned_state_object); // { name: "zak" }
console.log(state); // { name: "zak" }

如您所见,您已经有效地保存加载localStorage


更深入,更深入的解释:

使用setItem API的getItemlocalStorage方法。

然后可以通过name使用JSON.stringify和字符串对象进行保存。这很重要,因为storage api 允许保存字符串。 没有对象文字,没有数组等。

然后可以通过引用name并通过JSON.parse解析返回的String来加载。这将有效地将字符串重新水化为原始的对象/数组形式。

重要说明:存储在state 中的对象或数组中的所有引用在转换为字符串时都会中断。显然,字符串不能作为引用,所以这很有意义。为了解决这个问题,您可以创建一个解析器来重新设计引用,但这超出了此答案的范围。


我会承认一点意见,但是我认为这是一个广为人知的意见,那就是在使用Storage API时最好使用函数,因为它可以使编码更加清晰。下面是一个保存状态,加载状态并测试保存状态和加载状态是否相同以证明其概念的示例。

重要说明:您会注意到,在加载函数中,我们首先在raw_data中接收数据-这是因为如果密钥不存在(即第一个运行该程序时,您将不会保存数据),它将返回null。这是一个简单的健全性检查,如果不存在空对象,它将返回一个空对象-在您的情况下,您可能想抛出一个错误,但这取决于您。

StackOverflow不允许使用存储,它会出现,因此,如果您想查看运行的版本,请查看此随附的fiddle

let state = {
  items: [{
      id: 1,
      title: 'First item',
      commentsCount: 0,
      comments: [],
      displayComment: false
    },
    {
      id: 2,
      title: 'Second item',
      commentsCount: 0,
      comments: [],
      displayComment: false
    },
    {
      id: 3,
      title: 'Third item',
      commentsCount: 0,
      comments: [],
      displayComment: false
    },
  ],
  activeItem: {},
  isHidden: true
}


function saveAs(name, state_obj) {
  let data = JSON.stringify(state_obj);
  localStorage.setItem(name, data);
  console.log("saved!");
}

function loadFrom(name) {
  let raw_data, data;
  raw_data = localStorage.getItem(name);
  if (!raw_data) return {};
  data = JSON.parse(raw_data);
  return data;
}

function test(_old, _new) {
return JSON.stringify(_old) === JSON.stringify(_new);
}

saveAs("my_saved_state", state);
let myNewState = loadFrom("my_saved_state");

console.log( test(state, myNewState) ? "old and new are the same!" : "old and new are different" );