You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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;

关键修复点说明

  1. 移除tags状态:不再通过字符串拼接HTML,直接在JSX中渲染动态内容
  2. 替换dangerouslySetInnerHTML:用React原生的条件渲染和组件语法构建建议列表,确保事件绑定正确
  3. 修正事件传递:onClick={() => this.onClick(e.id)}通过箭头函数传递参数,同时保留组件上下文
  4. 优化数据处理:用find替代map查找选中项,提升性能;简化componentDidMount中的异步逻辑
  5. 修复OutsideClickHandler调用:传递this.onClickAway函数引用而非立即执行

内容的提问来源于stack exchange,提问作者jonathan Daboush

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 21:15:17