1

I'm trying to store an array of objects in local storage. I'm using this common method:

localStorage.setItem( 'products', JSON.stringify(this.state.products) );
let initialProducts = JSON.parse(localStorage.getItem("products") || "[]")

I'm getting the error:

SyntaxError: Unexpected token o in JSON at position 1

I know that error means I am parsing the JSON twice, however if I do not parse it, when I get "products" from localStorage it is:

[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]

What am I doing wrong?

Full code:

import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
import ProductList from "../products/ProductList";
import productData from "../products/model";

class App extends Component {
  constructor(props) {
    super(props);
    let initialProducts = JSON.parse(localStorage.getItem("products") || "[]")
    console.log(initialProducts);
    this.state = {
      newProductName: "",
      newProductPrice: 0,
      products: initialProducts
    };
  }

  updateNewProductName = event => {
    this.setState({ newProductName: event.target.value });
  };

  updateNewProductPrice = event => {
    this.setState({ newProductPrice: event.target.value });
  };

  addProduct = () => {
    this.state.products.push({
      name: this.state.newProductName,
      price: this.state.newProductPrice
    });
    this.setState({
      products: this.state.products
    });
    localStorage.setItem( 'products', JSON.stringify(this.state.products) );
  };

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <div className="App-header-container">
            <img
              src="https://www.ezyvet.com/wp-content/uploads/2016/04/ezyVet-Logo-22-4.png"
              alt="ezyVet Cloud Veterinary Practice Management Software"
              id="logo"
              className="App-logo"
              data-height-percentage="65"
              data-actual-width="768"
              data-actual-height="252"
            />
          </div>
        </header>
        <div className="App-header-container">
          <ProductList products={this.state.products} />
          <input
            type="text"
            id="uname"
            name="uname"
            required
            minLength="2"
            placeholder="name"
            value={this.state.newProductName}
            onChange={this.updateNewProductName}
          />
          <input
            type="number"
            id="uprice"
            name="uprice"
            required
            placeholder="price"
            value={this.state.newProductPrice}
            onChange={this.updateNewProductPrice}
          />
          <button onClick={this.addProduct}>Add Product</button>
        </div>
      </div>
    );
  }
}

export default App;
BeniaminoBaggins
  • 11,202
  • 41
  • 152
  • 287
  • Did you verify the raw string inside localstorage? Does it contain what you think it contains? – Nisarg Shah Aug 08 '18 at 07:01
  • @NisargShah I just did and the value is [object Object],[object Object],[object Object],[object Object],[object Object],[object Object]. Strange because in the example solution at the top of my question it sets the localStorage in the same fashion. – BeniaminoBaggins Aug 08 '18 at 07:07
  • if the`this.state.products` is mistakenly passed to `localStorage` as `localStorage.setItem('products',this.state.products)` instead of `localStorage.setItem('products',JSON.stringify(this.state.products))` then it will always be stored as `[object Object]` . Can you please check what is the value from `JSON.stringify(this.state.products)` before setting in localstorage? – vikscool Aug 08 '18 at 07:16
  • @vikscool `console.log(JSON.stringify(this.state.products));` gives `[{"name":"Sledgehammer","price":125.75},{"name":"Axe","price":190.5},{"name":"Bandsaw","price":562.13},{"name":"Chisel","price":12.9},{"name":"Hacksaw","price":18.45},{"name":"eeee","price":"02"}]` – BeniaminoBaggins Aug 08 '18 at 07:18
  • @BeniaminoBaggins Try logging `this.state.products` before invoking `localStorage.setItem`. I am suspecting it is already a string at that stage, so `JSON.stringify` doesn't affect it. – Nisarg Shah Aug 08 '18 at 07:21
  • @vikscool it is not a string: `0: {name: "Sledgehammer", price: 125.75} 1:{name: "Axe", price: 190.5} 2:{name: "Bandsaw", price: 562.13} 3:{name: "Chisel", price: 12.9} and so on..` – BeniaminoBaggins Aug 08 '18 at 07:25
  • @BeniaminoBaggins the `[object Object]` will only occur if you try to convert an `Object` to `String` and as in the `localStorage.setItem(key, value)` the value if not is `String` will be converted to `String`. So, as @NisargShah already suggested please take a look at the `this.state.products`. And please check if it not getting updated from any other location as `Object`instead of `String`. – vikscool Aug 08 '18 at 07:32
  • @vikscool this.state.products is `0: {name: "Sledgehammer", price: 125.75} 1:{name: "Axe", price: 190.5} 2:{name: "Bandsaw", price: 562.13} 3:{name: "Chisel", price: 12.9}` and so on.. – BeniaminoBaggins Aug 08 '18 at 07:34
  • @BeniaminoBaggins Can you create a working [mcve] in the question or on codepen/jsfiddle? – Nisarg Shah Aug 08 '18 at 07:44

1 Answers1

1

It works when I double up on the JSON.parse and JSON.stringify.

For example:

let initialProducts = JSON.parse(JSON.parse(localStorage.getItem("products")));
localStorage.setItem( 'products', JSON.stringify(JSON.stringify(this.state.products) ));

Might be something to do with the objects being nested inside the array.

BeniaminoBaggins
  • 11,202
  • 41
  • 152
  • 287