React组件默认/具名导出报错、useRef调用及Todo渲染问题求助
问题排查与解决方案
1. 导入导出错误修复
你最开始的报错是因为App.jsx中使用了默认导入语法引入List,但List.jsx最初是用命名导出的方式导出List,二者不匹配。
两种修复方案二选一:
- 方案1:修改
App.jsx的导入语法为命名导入:import { List } from './List',保留你最初的export {List, Render}导出方式 - 方案2:修改
List.jsx的导出为默认导出,和你后来改的一样:export default List; export { Render };,对应App.jsx的默认导入语法
2. useRef顶层调用错误修复
React Hook只能在函数组件内部顶层作用域或者自定义Hook中调用,你最开始把const inputRef = useRef()写在List组件外部,属于全局顶层调用,必然报错。
把inputRef移到List组件内部后,原来定义在全局的onClick、Render函数无法访问组件内部的inputRef变量,所以会报变量未定义的错误,同时你用全局变量todoItems存储待办数据,数据更新后无法触发React视图刷新,需要同步调整代码逻辑:
- 用
useState存储待办列表todoItems,替代全局变量 - 把
onClick逻辑移到List组件内部 - 待办列表渲染逻辑和输入逻辑整合到同一个组件,不需要拆分两个独立的
ReactDOM.render调用(你原来在index.js里调用两次ReactDOM.render会导致先渲染的App内容被后渲染的Render覆盖,且#list是嵌套在#root内部的,完全不需要两次渲染)
3. Render函数渲染问题解答
你写的Render函数不能正常渲染,原因有两个:
forEach方法没有返回值,你需要用map方法来遍历返回React元素数组- 遍历回调函数里的
<h1>{item}</h1>没有写return,不会生成可渲染的元素
修正后的渲染逻辑示例:
function Render({ todoItems }) { return todoItems.map((item, index) => <h1 key={index}>{item}</h1>); }
完整修正代码
List.jsx
import React, { useRef, useState } from 'react'; // 待办渲染组件 function Render({ todoItems }) { return todoItems.map((item, index) => <h1 key={index}>{item}</h1>); } // 输入组件 function List() { const inputRef = useRef(); // 用useState存储待办列表,更新时自动触发视图刷新 const [todoItems, setTodoItems] = useState([]); function onClick() { const newItem = inputRef.current.value.trim(); if (!newItem) return; setTodoItems(prev => [...prev, newItem]); inputRef.current.value = ''; console.log("Pushed item in the array!"); } return ( <div className="mainbox"> <div className="inputdiv"> <input type="text" ref={inputRef} placeholder="Enter Task..." className="textbox" id="taskName" /> <button className="button" onClick={onClick}>+</button> </div> {/* 直接在List组件内渲染待办,不需要单独调用ReactDOM.render */} <div className="todo-list"> <Render todoItems={todoItems} /> </div> </div> ); } export default List; export { Render };
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './components/App'; import './styles.css'; // React 18以后推荐用createRoot语法,旧版本可以保留原来的render写法 const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);
App.jsx
import React from 'react'; import List from './List'; function App() { return ( <div className="app"> <List /> </div> ); } export default App;
index.html 调整
把嵌套在#root内部的#list移除,不需要额外的挂载节点:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="https://fonts.googleapis.com/css?family=McLaren|Montserrat&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="./src/styles.css"> <title>Mandy's Todo-List App!</title> </head> <body> <div id="root"></div> </body> </html>
内容的提问来源于stack exchange,提问作者autonomous
相关产品推荐
相关产品推荐

