ReactJS报错:Cannot read properties of null (reading 'appendChild') 求助
问题:React组件报错“Cannot read properties of null (reading 'appendChild')”
页面加载失败,出现错误提示:
Cannot read properties of null (reading 'appendChild'),推测和DOM操作有关,找不到解决方法,相关代码如下:
import React from 'react' const Footer = () => { const boxContainer = document.querySelector(".boxContainer"); for (let i = 0; i < 365; i++) { const list = [0, 1, 2, 3, 41, 42, 43, 44, 82, 83, 123, 124, 125, 126, 164, 165, 166, 167, 205, 206, 246, 247, 287, 288, 5, 6, 46, 47, 87, 88, 128, 129, 169, 170, 210, 211, 251, 252, 292, 293, 8, 9, 14, 15, 49, 50, 51, 90, 91, 92, 131, 132, 133, 134, 172, 173, 213, 214, 254, 255, 295, 296, 175, 176, 217, 177, 218, 259, 55, 56, 96, 97, 137, 138, 178, 179, 219, 220, 260, 261, 217, 218, 259, 260, 261, 301, 302, 17, 18, 19, 58, 59, 60, 61, 99, 100, 102, 103, 140, 141, 144, 181, 182, 185, 222, 223, 225, 226, 263, 264, 265, 266, 304, 305, 306, 24, 25, 65, 66, 67, 106, 107, 108, 147, 148, 149, 150, 188, 189, 229, 230, 270, 271, 311, 312, 67, 108, 149, 150, 191, 232, 192, 233, 274, 234, 275, 316, 194, 235, 276, 154, 195, 236, 73, 114, 155, 33, 34, 74, 75, 115, 116, 156, 157, 197, 198, 238, 239, 279, 280, 320, 321, 36, 37, 38, 39, 77, 78, 79, 80, 118, 119, 159, 160, 161, 162, 200, 201, 202, 203, 241, 242, 282, 283, 284, 285, 323, 324, 325, 326, ]; const el = document.createElement("div"); el.classList = list.includes(i) ? "box active" : "box" boxContainer.appendChild(el) } return ( <div id="footer"> <div className="logo">LOGO</div> <h1 className="quote">Living, learning & levelling up one day at a time.</h1> <h2 className="githubTitle">Want to get in touch with me?</h2> <div className="githubChart"> <div className="dates"> <span>Jan</span> <span>Feb</span> <span>Mar</span> <span>Apr</span> <span>May</span> <span>Jun</span> <span>Jul</span> <span>Aug</span> <span>Sep</span> <span>Oct</span> <span>Nov</span> <span>Dec</span> </div> <div className="boxContainer"> <div className="box"></div> </div> </div> <div className="githubTitle">ON <span className="iconLinks">Github</span> <span className="iconLinks">LinkedIN</span> <span className="iconLinks">Instagram</span> </div> <div className="copyright">Copyright © 2023 Aaryan Pinto</div> </div> ) } export default Footer
问题原因
你在函数组件的顶层直接调用document.querySelector(".boxContainer"),此时组件还未完成渲染,DOM节点还没挂载到页面,所以返回null,调用appendChild自然会报错。React的执行逻辑是先运行组件函数体代码,再生成DOM并挂载,这时候DOM还不存在。
解决方法
React中优先用JSX语法生成元素,避免手动操作DOM,以下是两种可行方案:
方案一:用JSX直接生成元素(推荐)
把循环生成的box转换成数组,直接在JSX中渲染,符合React的核心范式:
import React from 'react' const Footer = () => { const list = [0, 1, 2, 3, 41, 42, 43, 44, 82, 83, 123, 124, 125, 126, 164, 165, 166, 167, 205, 206, 246, 247, 287, 288, 5, 6, 46, 47, 87, 88, 128, 129, 169, 170, 210, 211, 251, 252, 292, 293, 8, 9, 14, 15, 49, 50, 51, 90, 91, 92, 131, 132, 133, 134, 172, 173, 213, 214, 254, 255, 295, 296, 175, 176, 217, 177, 218, 259, 55, 56, 96, 97, 137, 138, 178, 179, 219, 220, 260, 261, 217, 218, 259, 260, 261, 301, 302, 17, 18, 19, 58, 59, 60, 61, 99, 100, 102, 103, 140, 141, 144, 181, 182, 185, 222, 223, 225, 226, 263, 264, 265, 266, 304, 305, 306, 24, 25, 65, 66, 67, 106, 107, 108, 147, 148, 149, 150, 188, 189, 229, 230, 270, 271, 311, 312, 67, 108, 149, 150, 191, 232, 192, 233, 274, 234, 275, 316, 194, 235, 276, 154, 195, 236, 73, 114, 155, 33, 34, 74, 75, 115, 116, 156, 157, 197, 198, 238, 239, 279, 280, 320, 321, 36, 37, 38, 39, 77, 78, 79, 80, 118, 119, 159, 160, 161, 162, 200, 201, 202, 203, 241, 242, 282, 283, 284, 285, 323, 324, 325, 326]; // 生成365个box元素的数组 const boxes = Array.from({ length: 365 }, (_, i) => ( <div key={i} className={list.includes(i) ? "box active" : "box"}></div> )) return ( <div id="footer"> <div className="logo">LOGO</div> <h1 className="quote">Living, learning & levelling up one day at a time.</h1> <h2 className="githubTitle">Want to get in touch with me?</h2> <div className="githubChart"> <div className="dates"> <span>Jan</span> <span>Feb</span> <span>Mar</span> <span>Apr</span> <span>May</span> <span>Jun</span> <span>Jul</span> <span>Aug</span> <span>Sep</span> <span>Oct</span> <span>Nov</span> <span>Dec</span> </div> <div className="boxContainer"> {/* 渲染生成的boxes数组 */} {boxes} </div> </div> <div className="githubTitle">ON <span className="iconLinks">Github</span> <span className="iconLinks">LinkedIN</span> <span className="iconLinks">Instagram</span> </div> <div className="copyright">Copyright © 2023 Aaryan Pinto</div> </div> ) } export default Footer
方案二:用useRef+useEffect操作DOM(仅当必须手动操作时)
如果一定要手动操作DOM,需要确保DOM已经挂载,用useRef获取节点,useEffect在组件挂载后执行:
import React, { useRef, useEffect } from 'react' const Footer = () => { const boxContainerRef = useRef(null); useEffect(() => { const list = [0, 1, 2, 3, 41, 42, 43, 44, 82, 83, 123, 124, 125, 126, 164, 165, 166, 167, 205, 206, 246, 247, 287, 288, 5, 6, 46, 47, 87, 88, 128, 129, 169, 170, 210, 211, 251, 252, 292, 293, 8, 9, 14, 15, 49, 50, 51, 90, 91, 92, 131, 132, 133, 134, 172, 173, 213, 214, 254, 255, 295, 296, 175, 176, 217, 177, 218, 259, 55, 56, 96, 97, 137, 138, 178, 179, 219, 220, 260, 261, 217, 218, 259, 260, 261, 301, 302, 17, 18, 19, 58, 59, 60, 61, 99, 100, 102, 103, 140, 141, 144, 181, 182, 185, 222, 223, 225, 226, 263, 264, 265, 266, 304, 305, 306, 24, 25, 65, 66, 67, 106, 107, 108, 147, 148, 149, 150, 188, 189, 229, 230, 270, 271, 311, 312, 67, 108, 149, 150, 191, 232, 192, 233, 274, 234, 275, 316, 194, 235, 276, 154, 195, 236, 73, 114, 155, 33, 34, 74, 75, 115, 116, 156, 157, 197, 198, 238, 239, 279, 280, 320, 321, 36, 37, 38, 39, 77, 78, 79, 80, 118, 119, 159, 160, 161, 162, 200, 201, 202, 203, 241, 242, 282, 283, 284, 285, 323, 324, 325, 326]; if (boxContainerRef.current) { for (let i = 0; i < 365; i++) { const el = document.createElement("div"); el.className = list.includes(i) ? "box active" : "box"; boxContainerRef.current.appendChild(el); } } }, []); // 空依赖数组确保只在挂载后执行一次 return ( <div id="footer"> <div className="logo">LOGO</div> <h1 className="quote">Living, learning & levelling up one day at a time.</h1> <h2 className="githubTitle">Want to get in touch
相关产品推荐
相关产品推荐

