我是 React.js 的新手,我正在使用 React.js 和 Bootstrap 创建一个 Notes takign 网站。为简单起见,我将笔记数据保存在本地存储中,但我将升级此应用以将笔记数据保存在 Firebase 中。但是,当我尝试从本地存储加载笔记并将它们显示在 id 'notes' 的 div 元素中时,它给出了以下错误:TypeError: Cannot set property 'innerHTML' of null
我想在加载所有 html 或其他所有内容后运行加载注释功能。 当我在所有 HTML 加载后使用按钮单击侦听器运行此函数时,它可以工作。
代码是:
import React from 'react';
import './Home.css';
function Home() {
const loadNotes = () => {
let notes = localStorage.getItem('notes');
let titles = localStorage.getItem('titles');
let notesObj;
let titlesObj;
if (notes == null) {
notesObj = [];
}
else {
notesObj = JSON.parse(notes);
}
if (titles == null) {
titlesObj = [];
}
else {
titlesObj = JSON.parse(titles);
}
let html = '';
notesObj.forEach(function (element, index) {
html += `<div class="noteCard my-2 mx-2 card" style="width: 18rem;" id = ${index}>
<div class="card-body">
<h5 class="card-title">Note</h5>
<p class="card-text">${element}</p>
<button id = ${index} onclick = 'deleteNote(this.id)' class="btn btn-primary"><i class="fa fa-trash" style="margin-right: 10px;"></i>Delete Note</button>
</div>
</div>`
});
titlesObj.forEach(function (er, i) {
html = html.replace('<h5 class="card-title">Note</h5>', `<h5 class="card-title">${er}</h5>`);
});
let notesElm = document.getElementById('notes');
if (notesObj.length != 0) {
notesElm.innerHTML = html;
}
else {
notesElm.innerHTML = `<h4>Nothing to show here.</h4>`;
}
console.log('Notes shown.')
}
const addNote = () => {
let addTxt = document.getElementById('addTxt');
let notes = localStorage.getItem('notes');
let addTitle = document.getElementById('addTitle');
let titles = localStorage.getItem('titles');
let notesObj;
let titlesObj;
if (notes == null) {
notesObj = [];
}
else {
notesObj = JSON.parse(notes);
}
if (titles == null) {
titlesObj = [];
}
else {
titlesObj = JSON.parse(titles);
}
notesObj.push(addTxt.value);
titlesObj.push(addTitle.value);
localStorage.setItem('notes', JSON.stringify(notesObj));
localStorage.setItem('titles', JSON.stringify(titlesObj));
addTxt.value = '';
addTitle.value = '';
loadNotes();
console.log("Note added.")
}
return (
<div className="home">
<style type="text/css">
{`
.btn {
margin-right: 10px;t
}
.home__mainTitle {
margin-top: 60px;
}
`}
</style>
<div class="container my-3">
<h1 class='home__mainTitle'>Welcome to Magic Notes</h1>
<div class="card">
<div class="card-body" id = 'editor'>
<h5 class="card-title">Add title</h5>
<div class="form-group">
<input className='home__formInput' type="text" class="form-control" id="addTitle" rows="3" placeholder="Title"></input>
</div>
<h5 class="card-title">Add notes</h5>
<div class="form-group">
<textarea class="form-control" id="addTxt" rows="3" placeholder="Notes"></textarea>
</div>
<button class="btn btn-primary" onClick={ addNote } id='addBtn'><i class="fa fa-plus-square"></i>Add Note</button>
<button class="btn btn-primary" id='clearAllBtn'><i class="fa fa-eraser"></i>Clear All</button>
</div>
</div>
<h1 className='home__notesTitle'>Your Notes</h1>
<hr/>
<div id="notes" class="row container-fluid">
{/* <!-- <div class="noteCard my-2 mx-2 card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Note 1</h5>
<p class="card-text"></p>
<a href="#" class="btn btn-primary">Delete Note</a>
</div>
</div> --> */}
{ loadNotes() }
</div>
</div>
</div>
);
}
export default Home;
对代码或问题描述中的任何错误表示感谢和抱歉。
答案 0 :(得分:1)
通过尝试访问 DOM 并直接设置 innerHTML,您有点与 React 的一些一般原则作斗争。
在这种特定情况下,它失败了,因为当您第一次尝试对其进行变异时,DOM 中实际上并不存在 div。
看看这个非常局部的重构:
import React, { useEffect, useState } from 'react';
import './Home.css';
function Home() {
const [notes, setNotes] = useState([]);
const [titles, setTitles] = useState([]);
useEffect(() => {
setNotes(JSON.parse(localStorage.getItem('notes')) ?? []);
setTitles(JSON.parse(localStorage.getItem('titles')) ?? []);
},[]);
const addNote = () => {
let addTxt = document.getElementById('addTxt');
let addTitle = document.getElementById('addTitle');
let newTitles = [...titles, addTitle.value];
let newNotes = [...notes, addTxt.value];
localStorage.setItem('notes', JSON.stringify(newNotes));
localStorage.setItem('titles', JSON.stringify(newTitles));
setNotes(newNotes)
setTitles(newTitles)
addTxt.value = '';
addTitle.value = '';
console.log("Note added.")
}
return (
<div className="home">
<style type="text/css">
{`
.btn {
margin-right: 10px;t
}
.home__mainTitle {
margin-top: 60px;
}
`}
</style>
<div class="container my-3">
<h1 class='home__mainTitle'>Welcome to Magic Notes</h1>
<div class="card">
<div class="card-body" id = 'editor'>
<h5 class="card-title">Add title</h5>
<div class="form-group">
<input className='home__formInput' type="text" class="form-control" id="addTitle" rows="3" placeholder="Title"></input>
</div>
<h5 class="card-title">Add notes</h5>
<div class="form-group">
<textarea class="form-control" id="addTxt" rows="3" placeholder="Notes"></textarea>
</div>
<button class="btn btn-primary" onClick={ addNote } id='addBtn'><i class="fa fa-plus-square"></i>Add Note</button>
<button class="btn btn-primary" id='clearAllBtn'><i class="fa fa-eraser"></i>Clear All</button>
</div>
</div>
<h1 className='home__notesTitle'>Your Notes</h1>
<hr/>
<div id="notes" class="row container-fluid">
{notes.map((note,index) => {
return <div class="noteCard my-2 mx-2 card" style={{width: '18rem'}} id={index}>
<div class="card-body">
<h5 class="card-title">{titles[index]}</h5>
<p class="card-text">{note}</p>
<button id={index} onclick='deleteNote(this.id)'
class="btn btn-primary"><i class="fa fa-trash" style={{marginRight: "10px;"}}></i>Delete Note</button>
</div>
</div>
})}
{notes.length === 0 ? <h4>Nothing to show here.</h4> : null}
</div>
</div>
</div>
);
}
export default Home;
注意我是如何使用 useState
来存储笔记和标题的。文档:https://reactjs.org/docs/hooks-state.html
useEffect
在组件挂载并从 localStorage 加载数据时调用。 https://reactjs.org/docs/hooks-effect.html
然后,在渲染的主体中,我没有调用 loadNotes
并尝试改变尚不存在的 DOM,而是map
notes
和 {{1 }} 进入渲染的内容。
请注意,这还不是完整的重构。例如,您可能希望向文本区域添加侦听器以自动跟踪内容,而不是使用 titles
拉取内容。此外,document.getElementById
尚未实现,useEffect 中对 localStorage 内容的测试非常少,等等。但是,这足以让您入门。
答案 1 :(得分:0)
发生此错误是因为 loadNotes()
被包裹在音符 div
中。因此,您可以检查是否首先使用 notes
条件创建了 if
div。
if (notesElm) {
if (notesObj.length != 0) {
notesElm.innerHTML = html;
}
else {
notesElm.innerHTML = `<h4>Nothing to show here.</h4>`;
}
}
以下是工作代码:
import React from 'react';
import './Home.css';
function Home() {
const loadNotes = () => {
let notes = localStorage.getItem('notes');
let titles = localStorage.getItem('titles');
let notesObj;
let titlesObj;
if (notes == null) {
notesObj = [];
}
else {
notesObj = JSON.parse(notes);
}
if (titles == null) {
titlesObj = [];
}
else {
titlesObj = JSON.parse(titles);
}
let html = '';
notesObj.forEach(function (element, index) {
html += `<div class="noteCard my-2 mx-2 card" style="width: 18rem;" id = ${index}>
<div class="card-body">
<h5 class="card-title">Note</h5>
<p class="card-text">${element}</p>
<button id = ${index} onclick = 'deleteNote(this.id)' class="btn btn-primary"><i class="fa fa-trash" style="margin-right: 10px;"></i>Delete Note</button>
</div>
</div>`
});
titlesObj.forEach(function (er, i) {
html = html.replace('<h5 class="card-title">Note</h5>', `<h5 class="card-title">${er}</h5>`);
});
let notesElm = document.getElementById('notes');
if (notesElm) {
if (notesObj.length != 0) {
notesElm.innerHTML = html;
}
else {
notesElm.innerHTML = `<h4>Nothing to show here.</h4>`;
}
}
console.log('Notes shown.')
}
const addNote = () => {
let addTxt = document.getElementById('addTxt');
let notes = localStorage.getItem('notes');
let addTitle = document.getElementById('addTitle');
let titles = localStorage.getItem('titles');
let notesObj;
let titlesObj;
if (notes == null) {
notesObj = [];
}
else {
notesObj = JSON.parse(notes);
}
if (titles == null) {
titlesObj = [];
}
else {
titlesObj = JSON.parse(titles);
}
notesObj.push(addTxt.value);
titlesObj.push(addTitle.value);
localStorage.setItem('notes', JSON.stringify(notesObj));
localStorage.setItem('titles', JSON.stringify(titlesObj));
addTxt.value = '';
addTitle.value = '';
loadNotes();
console.log("Note added.")
}
return (
<div className="home">
<style type="text/css">
{`
.btn {
margin-right: 10px;t
}
.home__mainTitle {
margin-top: 60px;
}
`}
</style>
<div class="container my-3">
<h1 class='home__mainTitle'>Welcome to Magic Notes</h1>
<div class="card">
<div class="card-body" id = 'editor'>
<h5 class="card-title">Add title</h5>
<div class="form-group">
<input className='home__formInput' type="text" class="form-control" id="addTitle" rows="3" placeholder="Title"></input>
</div>
<h5 class="card-title">Add notes</h5>
<div class="form-group">
<textarea class="form-control" id="addTxt" rows="3" placeholder="Notes"></textarea>
</div>
<button class="btn btn-primary" onClick={ addNote } id='addBtn'><i class="fa fa-plus-square"></i>Add Note</button>
<button class="btn btn-primary" id='clearAllBtn'><i class="fa fa-eraser"></i>Clear All</button>
</div>
</div>
<h1 className='home__notesTitle'>Your Notes</h1>
<hr/>
<div id="notes" class="row container-fluid">
{/* <!-- <div class="noteCard my-2 mx-2 card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Note 1</h5>
<p class="card-text"></p>
<a href="#" class="btn btn-primary">Delete Note</a>
</div>
</div> --> */}
{ loadNotes() }
</div>
</div>
</div>
);
}
export default Home;