最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React build creates errors in production - Stack Overflow

programmeradmin3浏览0评论

I'm new to React and I have followed a tutorial for a ToDo web app. After pletion, I built it for production without errors in the terminal. The issue occurs when I try to statically open with a serve -s build in order to see it locally. Initially, I get a glimpse of the content and then two errors popup that were not there in development with npm start server. The errors are:

react-dom.production.min.js:209 TypeError: Cannot read property 'length' of null
    at App.js:31
    at ro (react-dom.production.min.js:211)
    at vu (react-dom.production.min.js:257)
    at t.unstable_runWithPriority (scheduler.production.min.js:19)
    at Wl (react-dom.production.min.js:122)
    at hu (react-dom.production.min.js:257)
    at react-dom.production.min.js:256
    at j (scheduler.production.min.js:17)
    at MessagePort.E.port1.onmessage (scheduler.production.min.js:14)
Za @ react-dom.production.min.js:209
scheduler.production.min.js:14 Uncaught TypeError: Cannot read property 'length' of null
    at App.js:31
    at ro (react-dom.production.min.js:211)
    at vu (react-dom.production.min.js:257)
    at t.unstable_runWithPriority (scheduler.production.min.js:19)
    at Wl (react-dom.production.min.js:122)
    at hu (react-dom.production.min.js:257)
    at react-dom.production.min.js:256
    at j (scheduler.production.min.js:17)
    at MessagePort.E.port1.onmessage (scheduler.production.min.js:14)

From the message I understand that the faulty part is in my

App.js

import React, { useState } from "react";
import "./App.css";
//Importing Components
import Form from "./Components/Form";
import ToDoList from "./Components/ToDoList";
function App() {
  // eslint-disable-next-line
  const [inputText, setInputText] = useState("");
  const [todos, setTodos] = useState([]);
  const [status, setStatus] = useState("");
  const [filterTodos, setFilterTodos] = useState([]);

  const getLocalTodos = () => {
    setTodos(JSON.parse(localStorage.getItem("todos")));
  };
  React.useEffect(() => {
    switch (status) {
      case "pleted":
        setFilterTodos(todos.filter((todo) => todopleted === true));
        break;
      case "unpleted":
        setFilterTodos(todos.filter((todo) => todopleted === false));
        break;
      default:
        setFilterTodos(todos);
        break;
    }
    if (todos.length !== 0) {
      localStorage.setItem("todos", JSON.stringify(todos));
    }
  }, [todos, status]);
  React.useEffect(() => {
    getLocalTodos();
  }, []);
  return (
    <React.Fragment>
      <header>{inputText}</header>
      <Form
        setStatus={setStatus}
        todos={todos}
        setTodos={setTodos}
        InputText={inputText}
        setInputText={setInputText}
      />
      <ToDoList filterTodos={filterTodos} setTodos={setTodos} todos={todos} />
    </React.Fragment>
  );
}

export default App;

the part where I am saving the data to the localStorage. I'm checking the array against zero in order to prevent useEffect from emptying the localStorage data on the first load. How to fix the issue in the production version?

Below I have attached the rest of the code:

ToDoList.js

import React from "react";
import ToDo from "./ToDo";
const ToDoList = (props) => {
  return (
    <div className="todo-container">
      <ul className="todo-list">
        {props.filterTodos.map((todo) => {
          return (
            <ToDo
              todo={todo}
              todos={props.todos}
              setTodos={props.setTodos}
              key={todo.id}
              text={todo.text}
            />
          );
        })}
      </ul>
    </div>
  );
};
export default ToDoList;

ToDo.js

import React from "react"

const ToDo = props => {
    const deleteNote = () => {
        props.setTodos(props.todos.filter(e=>e.id !== props.todo.id))
    }
    const pletedHandler = () =>{
        props.setTodos(
            props.todos.map(item =>{
                if(item.id === props.todo.id){
                    return {
                        ...item, pleted: !itempleted
                    }
                }
                return item
            })
        )
    }

    return (
        <div className="ToDo">
            <li className={`todo-item ${props.todopleted ? "cool" : "notCool"}`}>{props.text}</li>
            <button onClick={pletedHandler} className='plete-btn'>
                Complete </button>
            <button onClick={deleteNote} className='trash-btn'>
                Trash </button>
        </div>
    )
}

export default ToDo

Form.js

import React from "react";

const Form = (props) => {
  const InputTextHandler = (e) => {
    props.setInputText(e.target.value);
  };
  const addNote = (e) => {
    e.preventDefault();
    props.setTodos([
      ...props.todos,
      { text: props.InputText, pleted: false, id: Math.random() },
    ]);
    props.setInputText("");
    console.log(props.InputText);
  };
  const statusHanlder = (e) => {
    props.setStatus(e.target.value);
  };
  return (
    <form>
      <input
        value={props.InputText}
        onChange={InputTextHandler}
        type="text"
        className="todo-input"
      />
      <button onClick={addNote} className="todo-button" type="submit">
        <i className="fas fa-plus-square">+</i>
      </button>
      <div className="select">
        <select onChange={statusHanlder} name="todos" className="filter-todo">
          <option value="all">All</option>
          <option value="pleted">Completed</option>
          <option value="unpleted">Unpleted</option>
        </select>
      </div>
    </form>
  );
};

export default Form;

Development view Production version in a static local server

I'm new to React and I have followed a tutorial for a ToDo web app. After pletion, I built it for production without errors in the terminal. The issue occurs when I try to statically open with a serve -s build in order to see it locally. Initially, I get a glimpse of the content and then two errors popup that were not there in development with npm start server. The errors are:

react-dom.production.min.js:209 TypeError: Cannot read property 'length' of null
    at App.js:31
    at ro (react-dom.production.min.js:211)
    at vu (react-dom.production.min.js:257)
    at t.unstable_runWithPriority (scheduler.production.min.js:19)
    at Wl (react-dom.production.min.js:122)
    at hu (react-dom.production.min.js:257)
    at react-dom.production.min.js:256
    at j (scheduler.production.min.js:17)
    at MessagePort.E.port1.onmessage (scheduler.production.min.js:14)
Za @ react-dom.production.min.js:209
scheduler.production.min.js:14 Uncaught TypeError: Cannot read property 'length' of null
    at App.js:31
    at ro (react-dom.production.min.js:211)
    at vu (react-dom.production.min.js:257)
    at t.unstable_runWithPriority (scheduler.production.min.js:19)
    at Wl (react-dom.production.min.js:122)
    at hu (react-dom.production.min.js:257)
    at react-dom.production.min.js:256
    at j (scheduler.production.min.js:17)
    at MessagePort.E.port1.onmessage (scheduler.production.min.js:14)

From the message I understand that the faulty part is in my

App.js

import React, { useState } from "react";
import "./App.css";
//Importing Components
import Form from "./Components/Form";
import ToDoList from "./Components/ToDoList";
function App() {
  // eslint-disable-next-line
  const [inputText, setInputText] = useState("");
  const [todos, setTodos] = useState([]);
  const [status, setStatus] = useState("");
  const [filterTodos, setFilterTodos] = useState([]);

  const getLocalTodos = () => {
    setTodos(JSON.parse(localStorage.getItem("todos")));
  };
  React.useEffect(() => {
    switch (status) {
      case "pleted":
        setFilterTodos(todos.filter((todo) => todo.pleted === true));
        break;
      case "unpleted":
        setFilterTodos(todos.filter((todo) => todo.pleted === false));
        break;
      default:
        setFilterTodos(todos);
        break;
    }
    if (todos.length !== 0) {
      localStorage.setItem("todos", JSON.stringify(todos));
    }
  }, [todos, status]);
  React.useEffect(() => {
    getLocalTodos();
  }, []);
  return (
    <React.Fragment>
      <header>{inputText}</header>
      <Form
        setStatus={setStatus}
        todos={todos}
        setTodos={setTodos}
        InputText={inputText}
        setInputText={setInputText}
      />
      <ToDoList filterTodos={filterTodos} setTodos={setTodos} todos={todos} />
    </React.Fragment>
  );
}

export default App;

the part where I am saving the data to the localStorage. I'm checking the array against zero in order to prevent useEffect from emptying the localStorage data on the first load. How to fix the issue in the production version?

Below I have attached the rest of the code:

ToDoList.js

import React from "react";
import ToDo from "./ToDo";
const ToDoList = (props) => {
  return (
    <div className="todo-container">
      <ul className="todo-list">
        {props.filterTodos.map((todo) => {
          return (
            <ToDo
              todo={todo}
              todos={props.todos}
              setTodos={props.setTodos}
              key={todo.id}
              text={todo.text}
            />
          );
        })}
      </ul>
    </div>
  );
};
export default ToDoList;

ToDo.js

import React from "react"

const ToDo = props => {
    const deleteNote = () => {
        props.setTodos(props.todos.filter(e=>e.id !== props.todo.id))
    }
    const pletedHandler = () =>{
        props.setTodos(
            props.todos.map(item =>{
                if(item.id === props.todo.id){
                    return {
                        ...item, pleted: !item.pleted
                    }
                }
                return item
            })
        )
    }

    return (
        <div className="ToDo">
            <li className={`todo-item ${props.todo.pleted ? "cool" : "notCool"}`}>{props.text}</li>
            <button onClick={pletedHandler} className='plete-btn'>
                Complete </button>
            <button onClick={deleteNote} className='trash-btn'>
                Trash </button>
        </div>
    )
}

export default ToDo

Form.js

import React from "react";

const Form = (props) => {
  const InputTextHandler = (e) => {
    props.setInputText(e.target.value);
  };
  const addNote = (e) => {
    e.preventDefault();
    props.setTodos([
      ...props.todos,
      { text: props.InputText, pleted: false, id: Math.random() },
    ]);
    props.setInputText("");
    console.log(props.InputText);
  };
  const statusHanlder = (e) => {
    props.setStatus(e.target.value);
  };
  return (
    <form>
      <input
        value={props.InputText}
        onChange={InputTextHandler}
        type="text"
        className="todo-input"
      />
      <button onClick={addNote} className="todo-button" type="submit">
        <i className="fas fa-plus-square">+</i>
      </button>
      <div className="select">
        <select onChange={statusHanlder} name="todos" className="filter-todo">
          <option value="all">All</option>
          <option value="pleted">Completed</option>
          <option value="unpleted">Unpleted</option>
        </select>
      </div>
    </form>
  );
};

export default Form;

Development view Production version in a static local server

Share Improve this question asked Sep 12, 2020 at 5:57 AtanasBAtanasB 1601 silver badge11 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

If there is no todos field inside localStorage then useEffect with getLocalTodos call sets "null" value for todos state.

Just change getLocalTodos like that:

const getLocalTodos = () => {
    setTodos(JSON.parse(localStorage.getItem("todos")) || []);
};

When first time rendering App. You get todos list from localStorage. But it nothing. So, your code always set todos and that case totos will be null.

Component App should check:

const getLocalTodos = () => {
    const cached = localStorage.getItem("todos") ? JSON.parse(localStorage.getItem("todos")) : null;

if (cached === null)
    return;

setTodos(cached);
};

Are you sure you have todos in your localStorage?

This function assumes you have todos in your localStorage which is probably not.

const getLocalTodos = () => {
    setTodos(JSON.parse(localStorage.getItem("todos")));
};

Without your todos in the localStorage

JSON.parse(localStorage.getItem("todos")) // returns undefined.

which messes up your todos state which is meant to be an array. Hence .length of undefined.

发布评论

评论列表(0)

  1. 暂无评论