使用dangerouslySetInnerHTML后点击建议项触发Uncaught TypeError错误
问题分析与解决方案
报错原因
你遇到的this.onClick is not a function错误,核心原因在于使用dangerouslySetInnerHTML渲染带事件处理的HTML字符串:
- 生成的HTML字符串中的
onClick事件不属于React的事件系统,无法绑定到组件实例的this上下文 - 代码中
onClick={this.onClick('+e.id+')}会立即执行函数,而非传递事件处理函数引用
此外,onGenerate方法中构建OutsideClickHandler的HTML字符串也是错误的,React组件不能通过字符串拼接的方式渲染。
修复方案
放弃用字符串拼接HTML的方式,直接在JSX中渲染建议列表和外部点击处理器,让React管理事件绑定和组件上下文。
修正后的完整代码
import React, { Component } from 'react'; import PropTypes from "prop-types"; import axios from 'axios'; import "bootstrap/dist/css/bootstrap.min.css"; import OutsideClickHandler from 'react-outside-click-handler'; class Country extends Component { static propTypes = { suggestions: PropTypes.instanceOf(Array) }; static defaultProps = { suggestions: [] }; emptyItem = { value: "", country: "" }; constructor(props) { super(props); this.state = { countryError: '', list: [], country: this.emptyItem, countryNames: [""], action: "", filterList: [], currentValue: "", isInvisible: true }; this.removeItem = this.removeItem.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.filterList = this.filterList.bind(this); this.onChange = this.onChange.bind(this); this.onClick = this.onClick.bind(this); this.onClickAway = this.onClickAway.bind(this); this.onGenerate = this.onGenerate.bind(this); } async componentDidMount() { let currentComponent = this; console.log('hi'); if (this.props.id && this.props.id !== -1) { let path = '/country'; try { const res = await axios.get(`http://localhost:8080${path}/${this.props.id}`); this.setState({ country: res }); } catch (error) { const emptyItem = { value: "" }; currentComponent.setState({ country: emptyItem }, () => { console.log(currentComponent.state.country); }); } } // 获取所有国家数据 try { const res = await axios.get('http://localhost:8080/country'); const fromList = res.data.map(e => ({ id: e.id, value: e.value })); this.setState({ list: fromList }); } catch (error) { console.error('获取国家列表失败:', error); } } filterList() { const { list, currentValue } = this.state; if (list.length <= 1) { this.setState({ filterList: [] }); return; } const newList = list.filter(e => e.value.startsWith(currentValue)); this.setState({ filterList: newList }); } async onClick(id) { const selectedItem = this.state.list.find(e => e.id === id); if (selectedItem) { await this.setState({ currentValue: selectedItem.value }); } await this.setState({ isInvisible: true }); } async onChange(event) { await this.setState({ currentValue: event.target.value }); await this.filterList(); await this.setState({ isInvisible: false }); } async onClickAway() { await this.setState({ filterList: [], isInvisible: true }); } async handleSubmit(event) { event.preventDefault(); let currentComponent = this; let path = '/country'; try { const res = await axios.post(`http://localhost:8080${path}`, this.state.currentValue); currentComponent.setState({ countryError: res.data }); window.location.reload(false); } catch (error) { currentComponent.setState({ countryError: "" }); window.location.reload(false); } } async removeItem() { let path = '/country'; const description = "无法删除该条目,因为它包含需要先删除的关联位置,或条目不存在。"; let currentComponent = this; try { await axios.delete(`http://localhost:8080${path}/${this.state.currentValue}`); } catch (error) { currentComponent.setState({ countryError: description }); } window.location.reload(false); } render() { const { filterList, isInvisible, currentValue, country, countryError } = this.state; return ( <div> <form onSubmit={this.handleSubmit}> <div><b>previous value:{country.value || ''}</b></div> <label>country:</label> <input type="text" id="fieldName" className="fieldName" onChange={this.onChange} value={currentValue} /> {/* 直接渲染建议列表,不再使用dangerouslySetInnerHTML */} {!isInvisible && ( <OutsideClickHandler onOutsideClick={this.onClickAway}> <div> {filterList.map((e, index) => ( <p key={index} onClick={() => this.onClick(e.id)}> {e.value} </p> ))} </div> </OutsideClickHandler> )} <div>{countryError}</div> <input type="submit" value="Submit" /> </form> <button onClick={this.removeItem}>Delete</button> </div> ); } } export default Country;
关键修复点说明
- 移除
tags状态:不再通过字符串拼接HTML,直接在JSX中渲染动态内容 - 替换
dangerouslySetInnerHTML:用React原生的条件渲染和组件语法构建建议列表,确保事件绑定正确 - 修正事件传递:
onClick={() => this.onClick(e.id)}通过箭头函数传递参数,同时保留组件上下文 - 优化数据处理:用
find替代map查找选中项,提升性能;简化componentDidMount中的异步逻辑 - 修复
OutsideClickHandler调用:传递this.onClickAway函数引用而非立即执行
内容的提问来源于stack exchange,提问作者jonathan Daboush
相关产品推荐
相关产品推荐

