单击表格单元格内的按钮时无法更新状态,React Ant Design

Posted

技术标签:

【中文标题】单击表格单元格内的按钮时无法更新状态,React Ant Design【英文标题】:Unable to update the state when button inside table cell clicked , React Ant Design 【发布时间】:2019-03-16 23:51:55 【问题描述】:

我想在点击表格单元格时更新状态。但是事件handleClick 没有触发。如果我在类外声明handleClick,则事件调用发生但状态未定义消息即将到来。

如果我们单击类外的其他单元格,如何更新状态。 下面是我的代码

import React from 'react';
import  connect  from 'react-redux';
import  bindActionCreators  from 'redux';
import  Table, Icon, Switch, Radio, Form, Divider, Button, Modal  from 'antd';

import * as productActions from './../../redux/actions/productActions';

const handleClick = (product) => 
  debugger;
  
  //UNABLE TO UPDATE STATE HERE
  // this.setState(
  //   visibleDeletePopup: true
  // );
  alert(JSON.stringify(product));


const columns = [
  title: 'Name',
  dataIndex: 'name',
  key: 'name',
  width: 150,
  render: text => <a href="javascript:;">text</a>,
, 
  title: 'Full',
  dataIndex: "stockIn['full']",
  key: `stockIn['full'`,
  width: 70,
,

  title: 'Half',
  dataIndex: "stockIn['half']",
  key: `stockIn['half'`,
  width: 70,
,

  title: 'Quarter',
  dataIndex: "stockIn['quarter']",
  key: `stockIn['quarter'`,
  width: 70,
,

  title: '90',
  dataIndex: "stockIn['ninty']",
  key: `stockIn['ninty']`,
  width: 70,
, 
  title: 'Category',
  dataIndex: 'category',
  key: 'category',
, 
  title: 'Action',
  key: 'action',
  width: 360,
  render: (text, record) => (<span>
    <button href="javascript:;" onClick=() => handleClick(record)>Edit-record.name</button>
    /* <Divider type="vertical" />
    <a href="javascript:;">Delete</a>
    <Divider type="vertical" />
    <a href="javascript:;" className="ant-dropdown-link">
      More actions <Icon type="down" />
    </a> */
  </span>
  ),
];


const showHeader = true;
let footer = () => 0;
const scroll =  y: 300 ;
const pagination =  position: 'bottom' ;


class ProductsPage extends React.Component 
  constructor(props) 
    super(props);
    this.onProductSave = this.onProductSave.bind(this);
    this.onChange = this.onChange.bind(this);

    this.state = 
      bordered: true,
      loading: false,
      pagination,
      size: 'small',
      expandedRowRender,
      title: title,
      showHeader,
      footer,
      rowSelection: ,
      hasData: true,
    ;

    //Popup and submit button
    this.state.buttonSubmitLoader = false;
    this.state.visibleDeletePopup = false;
  


  handleClick = (product) => 
    //UPDATE STATE // how?
  

  showModal = () => 
    this.setState(
      visibleDeletePopup: true,
    );
  

  handleOk = () => 
    this.setState( buttonSubmitLoader: true );
    setTimeout(() => 
      this.setState( buttonSubmitLoader: false, visibleDeletePopup: false );
    , 3000);
  

  handleCancel = () => 
    this.setState( visibleDeletePopup: false );
  


  render() 
    const state = this.state;
    return (
      <div>
        <div>
          <Table ...this.state
            columns=columns
            dataSource=state.hasData ? this.props.products : null
            footer=() => this.getFooterDetails(this.props.products)
            pagination= pageSize: 5 
          />
        </div>
       
      </div>
    );
  

  componentDidMount() 
    const props = this.props;
    props.actions.loadProducts();
  

  courseRow(item, index) 
    return <li key=index>item.name</li>;
  

  onProductSave(product) 

    this.props.actions.createProduct(product);
    this.setState(
      product: ""
    );
  

  onChange(e) 
    this.setState(
      product: e.target.value
    );
  

  getFooterDetails(products) 
    return <label class="text-success">Total Records Count is products.length</label>;
  




function mapStateToProps(state, ownProps) 
  //In state.products, product is coming from root reducer, if you change 
  //the name products to abhi_products , then here you need to call products:state.abhi_products 
  return 
    products: state.products
  


function mapDispatchToProps(dispatch) 
  return 
    actions: bindActionCreators(productActions, dispatch)
  


export default connect(mapStateToProps, mapDispatchToProps)(ProductsPage);

   

【问题讨论】:

【参考方案1】:

setState 仅在组件内有效。如果你想在声明的函数中执行 setState 并且想要执行 setState 则必须将此上下文传递给函数。

下面将在组件内工作

  handleClick = product => 
      this.setState(
         visibleDeletePopup: true
     );
  

更新:

整个组件代码可以修正如下

import React from 'react';
import  connect  from 'react-redux';
import  bindActionCreators  from 'redux';
import  Table, Icon, Switch, Radio, Form, Divider, Button, Modal  from 'antd';

import * as productActions from './../../redux/actions/productActions';


let footer = () => 0;


class ProductsPage extends React.Component 
  constructor(props) 
    super(props);
    this.state = 
      bordered: true,
      loading: false,
      pagination:  position: 'bottom' ,
      size: 'small',
      expandedRowRender,
      title: title,
      showHeader: true,
      footer,
      rowSelection: ,
      hasData: true,
    ;

     handleClick = product => 
        this.setState(
           visibleDeletePopup: true
       );
    
    //Popup and submit button
    this.state.buttonSubmitLoader = false; // never mutate state like this instead use setState method
    this.state.visibleDeletePopup = false;
  

  showModal = () => 
    this.setState(
      visibleDeletePopup: true,
    );
  

  handleOk = () => 
    this.setState( buttonSubmitLoader: true );
    setTimeout(() => 
      this.setState( buttonSubmitLoader: false, visibleDeletePopup: false );
    , 3000);
  

  handleCancel = () => 
    this.setState( visibleDeletePopup: false );
  

  componentDidMount() 
    const props = this.props;
    props.actions.loadProducts();
  

  courseRow = (item, index) => 
    return <li key=index>item.name</li>;
  

  onProductSave = product => 
    this.props.actions.createProduct(product);
    this.setState(
      product: ""
    );
  

  onChange = e => 
    this.setState(
      product: e.target.value
    );
  

  getFooterDetails = products => 
    return <label class="text-success">Total Records Count is products.length</label>;
  


  render() 
    const  hasData  = this.state;
    const  products  = this.props;
    const columns = [
      title: 'Name',
      dataIndex: 'name',
      key: 'name',
      width: 150,
      render: text => <a href="javascript:;">text</a>,
    , 
      title: 'Full',
      dataIndex: "stockIn['full']",
      key: `stockIn['full'`,
      width: 70,
    ,
    
      title: 'Half',
      dataIndex: "stockIn['half']",
      key: `stockIn['half'`,
      width: 70,
    ,
    
      title: 'Quarter',
      dataIndex: "stockIn['quarter']",
      key: `stockIn['quarter'`,
      width: 70,
    ,
    
      title: '90',
      dataIndex: "stockIn['ninty']",
      key: `stockIn['ninty']`,
      width: 70,
    , 
      title: 'Category',
      dataIndex: 'category',
      key: 'category',
    , 
      title: 'Action',
      key: 'action',
      width: 360,
      render: (text, record) => (<span>
        <button href="javascript:;" onClick=() => this.handleClick(record)>Edit-record.name</button>
      </span>
      ),
    ];
    return (
      <div>
        <div>
          <Table ...this.state
            columns=columns
            dataSource=hasData ? products : null
            footer=() => this.getFooterDetails(products)
            pagination= pageSize: 5 
          />
        </div>
      </div>
    );
  



const mapStateToProps = (state, ownProps) => 
  //In state.products, product is coming from root reducer, if you change 
  //the name products to abhi_products , then here you need to call products:state.abhi_products 
  return 
    products: state.products
  


const mapDispatchToProps = dispatch => 
  return 
    actions: bindActionCreators(productActions, dispatch)
  


export default connect(mapStateToProps, mapDispatchToProps)(ProductsPage);

【讨论】:

你能给我举个例子吗?如果我将 handleclick() 放在类中,则列渲染在类之外。它无法找到该方法。 (能不能同时显示html和js) 所以,你要求我在类本身中声明列,以便可以访问 handleClick 方法。 @Abhi 是的,这就是您需要在 react 中实现的方式,确保您将所有内容保存在组件中。我在回答中做了一些小的更正。现在可以了 检查并告诉我 我正在检查。antd 组件很大 (html, events) 。制作我的自定义组件并将antd组件放在里面还是保持原样(文件可能会越来越大)的最佳实践是什么【参考方案2】:

您可以像这样在类构造函数中声明列变量:

this.columns = []

事件将是(当然你需要绑定handleClick):

onClick=() => this.handleClick(record)

或者你可以像你一样在外面声明列并使用类上下文调用事件处理程序:

onClick=() => ProductsPage.prototype.handleClick(record)

【讨论】:

未捕获类型错误:ProductsPage.prototype.handleClick 不是函数【参考方案3】:
    enter code here

const getColumns = (handleClick) =>  // Note here
  return [
   
      title: 'Name',
  dataIndex: 'name',
  key: 'name',
  width: 150,
  render: text => <a href="javascript:;">text</a>,
, 
  title: 'Full',
  dataIndex: "stockIn['full']",
  key: `stockIn['full'`,
  width: 70,
,

  title: 'Half',
  dataIndex: "stockIn['half']",
  key: `stockIn['half'`,
  width: 70,
,

  title: 'Quarter',
  dataIndex: "stockIn['quarter']",
  key: `stockIn['quarter'`,
  width: 70,
,

  title: '90',
  dataIndex: "stockIn['ninty']",
  key: `stockIn['ninty']`,
  width: 70,
, 
  title: 'Category',
  dataIndex: 'category',
  key: 'category',
, 
  title: 'Action',
  key: 'action',
  width: 360,
  render: (text, record) => (<span>
    <button href="javascript:;" onClick=() => handleClick(record)>Edit-record.name</button>
    /* <Divider type="vertical" />
    <a href="javascript:;">Delete</a>
    <Divider type="vertical" />
    <a href="javascript:;" className="ant-dropdown-link">
      More actions <Icon type="down" />
    </a> */
  </span>
  ),
]

然后在你的组件里面

 <Table ...this.state
    columns=getColumns(this.handleClick) // and Here
    dataSource=state.hasData ? this.props.products : null
    footer=() => this.getFooterDetails(this.props.products)
    pagination= pageSize: 5 
   />

【讨论】:

【参考方案4】:

你可以使用列标签

<Table pagination=false dataSource=this.state.responsible>
    <Column title="name" dataIndex="name" key="name" />
    <Column title="Category" dataIndex="email" key="Category" />

  <Column title="Actions" dataIndex="Actions" key="Actions"
 render=(text, element, index)=>
   return (<div>
    <i className="fas fa-edit text-success m-1" style= cursor: "pointer" 
      onClick=() => this.handleClick()
    ></i>
    <i className="fas fa-trash text-danger m-1" style= cursor: "pointer" 
      onClick=() => this.Delete(element._id)
 
      
    ></i>

  </div>)
 
  />
      
      </Table>   

【讨论】:

以上是关于单击表格单元格内的按钮时无法更新状态,React Ant Design的主要内容,如果未能解决你的问题,请参考以下文章

Swift - 表格视图单元格内的单击按钮不会在该单元格的功能处调用确实选择行

快速单击其中一个 tableview 单元格内的按钮后重新加载 tableview

uitableview 单元格突出显示

表格视图在按钮单击时更新单元格时反弹

在单元格内单击时找出 UITableView 中的哪个部分按钮

Swift - 想要在单击集合视图单元格内的按钮时进行更改