Home > Enterprise >  Unexpected token u in JSON at position 0 in React.js todo app after deployment on netlify
Unexpected token u in JSON at position 0 in React.js todo app after deployment on netlify

Time:06-02

I am trying to deploy the react app on netlify. Locally, my react todo app is working fine and local storage is persisting the data as well (locally). but when I deployed the web app on netlify, after visiting the live link it's showing me this error: "Unexpected token u in JSON at position 0 at JSON.parse" as it is retrieving the undefined. Solutions I tried: checked the typo 2: checked the object in the console which is displaying the data correctly. 3: i also kept the getTodoFromLocal function inside App() function and kept initial state of const [todos, setTodos] = useState([]); (to empty array) but this is not persisting data on page reloads

my code App.js

import React, {useEffect, useState} from 'react';
import './App.css';
import { Header, Form, TodoList } from './components';


// get data from local
const getTodoFromLocal = () => {
  if(localStorage.getItem("todos") === null){
    localStorage.setItem("todos", JSON.stringify([]));
  } else {
      try{
        let localTodo = localStorage.getItem("todos");
        let parsedTodo = JSON.parse(localTodo)
        return parsedTodo; 
      } catch(error) {
        console.log(error);
      }
   }
 }

const App = () => {
  // states
  const [inputText, setInputText] = useState("");
  const [todos, setTodos] = useState(getTodoFromLocal());
  const [status, setStatus] = useState("all");
  const [filteredTodo, setFilteredTodo] = useState([]);

  // run this only once when app loads
  useEffect(() => {
    getTodoFromLocal();
  }, [])

  // Run once when app loads and every time when there is any change in todos ot status
  useEffect(() => {
    filterHandler();
    saveToLocal();
  }, [todos, status])

  // functions
  const filterHandler = () =>{
    switch (status) {
      case 'completed':
       setFilteredTodo(todos.filter(todo => todo.completed === true));
       break;
      case 'incompleted':
        setFilteredTodo(todos.filter(todo => todo.completed === false));
        break;
      default:
        setFilteredTodo(todos);
        break;
    }
  }

  // save to local storage / set todos;
  const saveToLocal = () => {
    localStorage.setItem("todos", JSON.stringify(todos));
  };
  

  return (
    <div className="App">
      <Header />
      <Form inputText = {inputText} 
        setInputText={setInputText} 
        todos={todos}  
        setTodos={setTodos} 
        setStatus={setStatus}
        />
      <TodoList 
        todos={todos} 
        setTodos={setTodos} 
        filteredTodo={filteredTodo}
      />
    </div>
  );
}

export default App;

TodoList.js

import React from 'react';
import TodoItem from './TodoItem';

const TodoList = ({todos, setTodos, filteredTodo}) =>  {
  return (
    <div className='todo-container'>
        <ul className='todo-list'>
          {filteredTodo && filteredTodo.map(todo => (
            <TodoItem 
              key={todo.id} 
              todo={todo} 
              todos={todos} 
              setTodos={setTodos}
              text={todo.text}
              />
          ))}
        </ul>
    </div>
  )
}

export default TodoList;

Form.js

import React from 'react';
import './form.css';
import { v4 as uuidv4 } from 'uuid';


function Form({inputText, setInputText, todos, setTodos, setStatus}) {

  const inputHandler = (e) => {
    setInputText(e.target.value);
  }

  const submitHandler = (e) =>{
    e.preventDefault();
    // generate unique id for todo lists.
    const uniqueId = uuidv4(); 
    //add todo object on click of button
    const addItem = !inputText ? alert("enter somthing")  :  setTodos([
      ...todos, {id: uniqueId, text: inputText, completed: false }
    ]);
 
    //reset the input field after adding todo
    setInputText("");

    return addItem;
  }

  // filtered todo
  const statusTodo = (e) => {
    setStatus(e.target.value);
  }

  return (
    <form>
        <input  type="text" className="todo-input" onChange={inputHandler} value={inputText}/>
        <button className="todo-button" type="submit" onClick={submitHandler}>
            <i className="fas fa-plus-square"></i>
        </button>
        <div className="select">
          <select onChange={statusTodo} name="todos" className="filter-todo">
              <option value="all">All</option>
              <option value="completed">Completed</option>
              <option value="incompleted">Incompleted</option>
          </select>
          <span><i className="fas fa-chevron-down"></i></span>
        </div>
  </form>
  )
}

export default Form;

TodoItem.js

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

const TodoItem = ({text, todo, todos, setTodos}) => {
  //delete an item;
  const deleteHandler = () => {
    setTodos(todos.filter(el => el.id !== todo.id))
  }

  const completeHandler = () => {
    setTodos(todos.map((item )=> {
      if(item.id === todo.id){
        return {
          ...item, completed: !todo.completed
        }
      }
      return item;
    }));
  }

  return (
    <div className='todo'>
        <li className={`todo-item ${todo.completed ? 'completed' : "" }`}>{text}</li>
        <button className='complete-btn' onClick={completeHandler}>
            <i className='fas fa-check'></i>
        </button> 
        <button className='trash-btn' onClick={deleteHandler}>
            <i className='fas fa-trash'></i>
        </button> 
    </div>
  )
}

export default TodoItem;

Live link: https://clinquant-parfait-ceab31.netlify.app/

Github link: https://github.com/Mehreen57/Todo-app-react

I hope I have explained the issue. I will be thankful to all of you who can help me in this regard.

Thank you in advance.

CodePudding user response:

I figured the error. Going step by step.

  1. You have getTodoFromLocal which is called when you setTodos const [todos, setTodos] = useState(getTodoFromLocal()); here.

  2. As localStorage.getItem("todos") is null, you set todos to [] but do not return anything which returns undefined and value of todos is changed to undefined.

  3. Then you have the function saveToLocal in which you store todos in localStorage.which is called in useEffect whenever todos change.

  4. Todos changed to undefined > useEffect is called > in saveToLocal function todos(undefined) is stored in localStorage.

updated code:

if (localStorage.getItem("todos") === null) {
    localStorage.setItem("todos", JSON.stringify([]));
    return []
  }
  • Related