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

React中无法通过MDBDataTable行内onClick事件更新state的问题

问题原因

你遇到的是闭包陷阱:点击「Load Table」时,loadTable函数会把包含setMe、getMe的JSX存入data状态,此时这两个函数捕获的是当时的cropName值(空字符串)。后续点击「set me!」更新cropName后,按钮绑定的还是旧的getMe函数,它依然引用着旧的闭包值,所以打印出来始终是空字符串。

解决方案

方法1:用useRef保存最新状态值

通过useRef存储cropName的最新值,绕过闭包限制:

import React, { useState, useRef, useEffect } from 'react';
import { render } from 'react-dom';
import { MDBDataTable } from 'mdbreact';
import './style.css';

import '@fortawesome/fontawesome-free/css/all.min.css';
import 'bootstrap-css-only/css/bootstrap.min.css';
import 'mdbreact/dist/css/mdb.css';

function App() {
  const [cropName, setCropName] = useState('');
  const cropNameRef = useRef('');
  const [data, setData] = useState([]);

  // 同步ref与state的最新值
  useEffect(() => {
    cropNameRef.current = cropName;
  }, [cropName]);

  function setMe(e) {
    setCropName('Hello');
  }

  function getMe(e) {
    console.log(cropNameRef.current); // 直接读取ref的最新值
  }

  function loadTable() {
    setData({
      columns: [
        { label: 'Action', field: 'radio', sort: 'asc', width: 150 },
        { label: 'Position', field: 'position', sort: 'asc', width: 270 },
        { label: 'Office', field: 'office', sort: 'asc', width: 200 },
        { label: 'Age', field: 'age', sort: 'asc', width: 100 },
        { label: 'Start date', field: 'date', sort: 'asc', width: 150 },
        { label: 'Salary', field: 'salary', sort: 'asc', width: 100 },
      ],
      rows: [
        {
          radio: (
            <div className="field-input pt-2">
              Click this
              <button onClick={setMe}>set me!</button>
              <button onClick={getMe}>get me!</button>
            </div>
          ),
          position: 'System Architect',
          office: 'Edinburgh',
          age: '61',
          date: '2011/04/25',
          salary: '$320',
        },
        {
          position: 'Accountant',
          office: 'Tokyo',
          age: '63',
          date: '2011/07/25',
          salary: '$170',
        },
      ],
    });
  }

  return (
    <div>
      <MDBDataTable striped bordered hover data={data} />
      <button onClick={loadTable}>Load Table</button>
    </div>
  );
}

render(<App />, document.getElementById('root'));

方法2:动态生成表格数据,避免闭包固化

不将表格数据存入state,而是每次渲染时动态生成,让getMe总能捕获最新的cropName:

import React, { useState } from 'react';
import { render } from 'react-dom';
import { MDBDataTable } from 'mdbreact';
import './style.css';

import '@fortawesome/fontawesome-free/css/all.min.css';
import 'bootstrap-css-only/css/bootstrap.min.css';
import 'mdbreact/dist/css/mdb.css';

function App() {
  const [cropName, setCropName] = useState('');
  const [showTable, setShowTable] = useState(false); // 仅控制表格显示状态

  function setMe(e) {
    setCropName('Hello');
  }

  function getMe(e) {
    console.log(cropName);
  }

  // 动态生成表格数据,每次渲染都是最新的函数引用
  const tableData = {
    columns: [
      { label: 'Action', field: 'radio', sort: 'asc', width: 150 },
      { label: 'Position', field: 'position', sort: 'asc', width: 270 },
      { label: 'Office', field: 'office', sort: 'asc', width: 200 },
      { label: 'Age', field: 'age', sort: 'asc', width: 100 },
      { label: 'Start date', field: 'date', sort: 'asc', width: 150 },
      { label: 'Salary', field: 'salary', sort: 'asc', width: 100 },
    ],
    rows: [
      {
        radio: (
          <div className="field-input pt-2">
            Click this
            <button onClick={setMe}>set me!</button>
            <button onClick={getMe}>get me!</button>
          </div>
        ),
        position: 'System Architect',
        office: 'Edinburgh',
        age: '61',
        date: '2011/04/25',
        salary: '$320',
      },
      {
        position: 'Accountant',
        office: 'Tokyo',
        age: '63',
        date: '2011/07/25',
        salary: '$170',
      },
    ],
  };

  return (
    <div>
      {showTable && <MDBDataTable striped bordered hover data={tableData} />}
      <button onClick={() => setShowTable(true)}>Load Table</button>
    </div>
  );
}

render(<App />, document.getElementById('root'));

方法特点

  • 方法1适合需要缓存表格数据的场景,通过ref同步最新状态;
  • 方法2更简洁,从根源上避免将JSX存入state导致的闭包问题。

内容的提问来源于stack exchange,提问作者Salvino D'sa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 01:25:12