React TodoList组件引入自定义<List>子组件后页面无法渲染问题求助
嘿,我发现你遇到的问题根源很明确——是组件引用的方式出错啦!
问题核心原因
你在TodoList类内部定义了List这个子组件,但在render方法里直接写<List items={this.state.items}/>,JavaScript会把List当成全局变量查找,根本找不到它(因为它是挂在TodoList实例上的类属性),直接导致组件渲染报错,页面就变成空白了。
另外还有几个小细节可以优化,顺便帮你一起修正了:
修正后的完整可运行代码
class TodoList extends React.Component { // 把List作为类属性定义没问题,但要记得用this调用 List = (props) => ( <ul> {props.items.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> ); state = { term: '', items: [] }; onChange = (event) => { this.setState({ term: event.target.value }); }; onSubmit = (event) => { event.preventDefault(); // 用函数式更新this.state更安全,避免状态依赖问题 this.setState(prevState => ({ term: '', items: [...prevState.items, prevState.term] })); }; render() { // 关键修正:这里必须用this.List来引用类内部的子组件 return ( <> <div> <h2>Todo List</h2> <form className="App" onSubmit={this.onSubmit}> <input value={this.state.term} onChange={this.onChange} /> <button>Submit</button> </form> {/* 这里改成this.List就正常了 */} <this.List items={this.state.items} /> </div> <style>{` .is-done { text-decoration: line-through; } `}</style> </> ); } } // 别忘了把组件挂载到页面的DOM元素上(比如id为root的div) ReactDOM.render(<TodoList />, document.getElementById('root'));
更推荐的优化方案
其实把子组件定义在类外面会更合理,既不用纠结this的引用问题,性能也更好(不会每次父组件渲染都重新创建子组件):
// 把List组件移到TodoList类外部 const List = (props) => ( <ul> {props.items.map((item, index) => ( <li key={index}>{item}</li> ))} </ul> ); class TodoList extends React.Component { // ... 其他代码和之前一样 render() { // 现在直接用<List />就可以了 return ( <> <div> <h2>Todo List</h2> <form className="App" onSubmit={this.onSubmit}> <input value={this.state.term} onChange={this.onChange} /> <button>Submit</button> </form> <List items={this.state.items} /> </div> <style>{` .is-done { text-decoration: line-through; } `}</style> </> ); } } ReactDOM.render(<TodoList />, document.getElementById('root'));
额外的功能优化建议
既然你写了.is-done的样式,不如顺便实现待办项的完成状态切换功能,让你的TodoList更实用:
- 给每个待办项添加唯一ID和完成状态字段
- 实现点击切换完成状态的方法
- 绑定样式到完成的项
代码示例:
const List = (props) => ( <ul> {props.items.map((item) => ( <li key={item.id} className={item.done ? 'is-done' : ''} onClick={() => props.toggleDone(item.id)} > {item.text} </li> ))} </ul> ); class TodoList extends React.Component { state = { term: '', items: [] }; onChange = (event) => { this.setState({ term: event.target.value }); }; onSubmit = (event) => { event.preventDefault(); if (!this.state.term.trim()) return; // 避免添加空项 this.setState(prevState => ({ term: '', items: [...prevState.items, { id: Date.now(), text: prevState.term, done: false }] })); }; toggleDone = (itemId) => { this.setState(prevState => ({ items: prevState.items.map(item => item.id === itemId ? {...item, done: !item.done} : item ) })); }; render() { return ( <> <div> <h2>Todo List</h2> <form className="App" onSubmit={this.onSubmit}> <input value={this.state.term} onChange={this.onChange} placeholder="添加待办项..." /> <button>Submit</button> </form> <List items={this.state.items} toggleDone={this.toggleDone} /> </div> <style>{` .is-done { text-decoration: line-through; color: #999; } li { cursor: pointer; margin: 8px 0; } `}</style> </> ); } } ReactDOM.render(<TodoList />, document.getElementById('root'));
内容的提问来源于stack exchange,提问作者rohit
相关产品推荐
相关产品推荐

