首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么这些功能不在主要的功能组件中?

为什么这些功能不在主要的功能组件中?
EN

Stack Overflow用户
提问于 2021-05-20 20:52:02
回答 1查看 59关注 0票数 2

我不明白为什么这些格式化程序函数被放置在名为TemplateTable的主组件之外。

例如,如果您需要使用actionformatter,您不能传递一个分派函数,对吗?

我遇到了一个问题,试图将删除按钮的actionformatter设置为调度(deleteTemplate())。

当操作格式化程序在主组件TemplateTable之外运行代码时,我得到的分派是未定义的。当我在组件中定义分派时,我显然得到了不能使用react的函数组件问题。

我只需在templateTable块中包含actionformatter,就可以解决整个问题。我只是觉得自己很简单,想知道是否有人对此有任何意见。

代码语言:javascript
复制
import React, { createRef, Fragment, useState, useEffect} from 'react';
import {
  Button,
  Card,
  CardBody,
  Col,
  CustomInput,
  DropdownItem,
  DropdownMenu,
  DropdownToggle,
  InputGroup,
  Media,
  Modal,
  ModalBody,
  Row,
  UncontrolledDropdown
} from 'reactstrap';
import { connect, useDispatch } from 'react-redux';
import FalconCardHeader from '../common/FalconCardHeader';
import ButtonIcon from '../common/ButtonIcon';
import paginationFactory, { PaginationProvider } from 'react-bootstrap-table2-paginator';
import BootstrapTable from 'react-bootstrap-table-next';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Link } from 'react-router-dom';
import Flex from '../common/Flex';
import Avatar from '../common/Avatar';
import { getPaginationArray } from '../../helpers/utils';
import CreateTemplate from '../templates/CreateTemplate';
import customers from '../../data/e-commerce/customers';
import { listTemplates, deleteTemplate } from '../../actions/index';


const nameFormatter = (dataField, { template }) => {
  return (
    <Link to="/pages/customer-details">
      <Media tag={Flex} align="center">
        <Media body className="ml-2">
          <h5 className="mb-0 fs--1">{template}</h5>
        </Media>
      </Media>
    </Link>
  );
};

const bodyFormatter = (dataField, { avatar, body }) => {
  return (
    <Link to="/pages/customer-details">
      <Media tag={Flex} align="center">
        
        <Media body className="ml-2">
          <h5 className="mb-0 fs--1">{body}</h5>
        </Media>
      </Media>
    </Link>
  );
};

const emailFormatter = email => <a href={`mailto:${email}`}>{email}</a>;
const phoneFormatter = phone => <a href={`tel:${phone}`}>{phone}</a>;

const actionFormatter = (dataField, { _id }) => ( 
  // Control your row with this id
  
  <UncontrolledDropdown>
    <DropdownToggle color="link" size="sm" className="text-600 btn-reveal mr-3">
      <FontAwesomeIcon icon="ellipsis-h" className="fs--1" />
    </DropdownToggle>
    <DropdownMenu right className="border py-2">
      <DropdownItem onClick={() => console.log('Edit: ', _id)}>Edit</DropdownItem>
      <DropdownItem onClick={} className="text-danger">
        Delete
      </DropdownItem>
    </DropdownMenu>
  </UncontrolledDropdown>
  );

const columns = [
  {
    dataField: 'name',

    text: 'Name',
    headerClasses: 'border-0',
    classes: 'border-0 py-2 align-middle',
    formatter: nameFormatter,
    sort: true
  },
  {
    dataField: 'content',
    headerClasses: 'border-0',
    text: 'Content',
    classes: 'border-0 py-2 align-middle',
    formatter: bodyFormatter,
    sort: true
  },
  {
    dataField: 'joined',
    headerClasses: 'border-0',
    text: 'Last modified',
    classes: 'border-0 py-2 align-middle',
    sort: true,
    align: 'right',
    headerAlign: 'right'
  },
  {
    dataField: '',
    headerClasses: 'border-0',
    text: 'Actions',
    classes: 'border-0 py-2 align-middle',
    formatter: actionFormatter,
    align: 'right'
  }
];

const SelectRowInput = ({ indeterminate, rowIndex, ...rest }) => (
  <div className="custom-control custom-checkbox">
    <input
      className="custom-control-input"
      {...rest}
      onChange={() => {}}
      ref={input => {
        if (input) input.indeterminate = indeterminate;
      }}
    />
    <label className="custom-control-label" />
  </div>
);

const selectRow = onSelect => ({
  mode: 'checkbox',
  columnClasses: 'py-2 align-middle',
  clickToSelect: false,
  selectionHeaderRenderer: ({ mode, ...rest }) => <SelectRowInput type="checkbox" {...rest} />,
  selectionRenderer: ({ mode, ...rest }) => <SelectRowInput type={mode} {...rest} />,
  headerColumnStyle: { border: 0, verticalAlign: 'middle' },
  selectColumnStyle: { border: 0, verticalAlign: 'middle' },
  onSelect: onSelect,
  onSelectAll: onSelect
});



const TemplateTable = ( props ) => {
  
  let table = createRef();
  // State
  const [isSelected, setIsSelected] = useState(false);
  const [showTemplateModal, setShowTemplateModal] = useState(false);
  const handleNextPage = ({ page, onPageChange }) => () => {
    onPageChange(page + 1);
  };


  const dispatch = useDispatch()
  const deleteHandler = (_id) => {
    dispatch(deleteHandler())
  }
  
 useEffect(() => {
  dispatch(listTemplates())
}, [])
  
  const handlePrevPage = ({ page, onPageChange }) => () => {
    onPageChange(page - 1);
  };

  const onSelect = () => {
    setImmediate(() => {
      setIsSelected(!!table.current.selectionContext.selected.length);
    });
  };

  const options = {
  
    custom: true,
    sizePerPage: 12,
    totalSize: props.templates.length
    
  };
  
  return (
    <Card className="mb-3">
      <FalconCardHeader light={false}>
      
        {isSelected ? (
          <InputGroup size="sm" className="input-group input-group-sm">
            <CustomInput type="select" id="bulk-select">
              <option>Bulk actions</option>
              <option value="Delete">Delete</option>
              <option value="Archive">Archive</option>
            </CustomInput>
            <Button color="falcon-default" size="sm" className="ml-2">
              Apply
            </Button>
          </InputGroup>
        ) : (
          <Fragment>
            <ButtonIcon onClick={(() => setShowTemplateModal(true))}icon="plus" transform="shrink-3 down-2" color="falcon-default" size="sm">
              New Template
            </ButtonIcon>
            <Modal isOpen={showTemplateModal} centered toggle={() => setShowTemplateModal(!showTemplateModal)}>
          <ModalBody className="p-0">
            <Card>
              <CardBody className="fs--1 font-weight-normal p-4"> 
                <CreateTemplate />
              </CardBody>
            </Card>
          </ModalBody>
        </Modal>
            <ButtonIcon icon="fa-download" transform="shrink-3 down-2" color="falcon-default" size="sm" className="mx-2">
              Download
            </ButtonIcon>
            <ButtonIcon icon="external-link-alt" transform="shrink-3 down-2" color="falcon-default" size="sm">
              Expand View
            </ButtonIcon>
          </Fragment>
        )}
      </FalconCardHeader>
      <CardBody className="p-0">
        <PaginationProvider pagination={paginationFactory(options)}>
          {({ paginationProps, paginationTableProps }) => {
            const lastIndex = paginationProps.page * paginationProps.sizePerPage;
            
            return (
              <Fragment>
                
                <div className="table-responsive">
                  <BootstrapTable
                    ref={table}
                    bootstrap4
                    keyField="_id"
                    data={props.templates}
                    columns={columns}
                    selectRow={selectRow(onSelect)}
                    bordered={false}
                    classes="table-dashboard table-striped table-sm fs--1 border-bottom border-200 mb-0 table-dashboard-th-nowrap"
                    rowClasses="btn-reveal-trigger border-top border-200"
                    headerClasses="bg-200 text-900 border-y border-200"
                    {...paginationTableProps}
                  />
                </div>
                <Row noGutters className="px-1 py-3 flex-center">
                  <Col xs="auto">
                    <Button
                      color="falcon-default"
                      size="sm"
                      onClick={handlePrevPage(paginationProps)}
                      disabled={paginationProps.page === 1}
                    >
                      <FontAwesomeIcon icon="chevron-left" />
                    </Button>
                    {getPaginationArray(paginationProps.totalSize, paginationProps.sizePerPage).map(pageNo => (
                      <Button
                        color={paginationProps.page === pageNo ? 'falcon-primary' : 'falcon-default'}
                        size="sm"
                        className="ml-2"
                        onClick={() => paginationProps.onPageChange(pageNo)}
                        key={pageNo}
                      >
                        {pageNo}
                      </Button>
                    ))}
                    <Button
                      color="falcon-default"
                      size="sm"
                      className="ml-2"
                      onClick={handleNextPage(paginationProps)}
                      disabled={lastIndex >= paginationProps.totalSize}
                    >
                      <FontAwesomeIcon icon="chevron-right" />
                    </Button>
                  </Col>
                </Row>
              </Fragment>
            );}
          }
        </PaginationProvider>
      </CardBody>
    </Card>
  );
};

const mapStateToProps = (state) => {
  return {
    templates: state.templates,
    auth: state.auth,
    deleteTemplate: state.deleteTemplate
  }
}

export default connect(mapStateToProps, { listTemplates })(TemplateTable);
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-20 22:54:17

简单的回答是,对于消费组件不存在任何依赖,因此从TemplateTable组件中将这些声明具体化是完全合理的。

虽然您可以将代码移回组件中,以关闭功能组件主体的附件中的任何依赖项,但我认为我们可以做得更好。

我建议将dispatch函数运行到任何需要它的特定格式化程序,即

代码语言:javascript
复制
const actionFormatter = ({ dispatch }) => (dataField, { _id }) => ( 
  // Control your row with this id
  
  <UncontrolledDropdown>
    <DropdownToggle color="link" size="sm" className="text-600 btn-reveal mr-3">
      <FontAwesomeIcon icon="ellipsis-h" className="fs--1" />
    </DropdownToggle>
    <DropdownMenu right className="border py-2">
      <DropdownItem onClick={() => console.log('Edit: ', _id)}>Edit</DropdownItem>
      <DropdownItem
        onClick={() => dispatch(deleteTemplate())}
        className="text-danger"
      >
        Delete
      </DropdownItem>
    </DropdownMenu>
  </UncontrolledDropdown>
);

并将columns转换为工厂函数,以便接收和传递配置,即

代码语言:javascript
复制
const columns = ({ dispatch }) => ([ // <-- consume config & destructure
  {
    dataField: 'name',

    text: 'Name',
    headerClasses: 'border-0',
    classes: 'border-0 py-2 align-middle',
    formatter: nameFormatter,
    sort: true
  },
  {
    dataField: 'content',
    headerClasses: 'border-0',
    text: 'Content',
    classes: 'border-0 py-2 align-middle',
    formatter: bodyFormatter,
    sort: true
  },
  {
    dataField: 'joined',
    headerClasses: 'border-0',
    text: 'Last modified',
    classes: 'border-0 py-2 align-middle',
    sort: true,
    align: 'right',
    headerAlign: 'right'
  },
  {
    dataField: '',
    headerClasses: 'border-0',
    text: 'Actions',
    classes: 'border-0 py-2 align-middle',
    formatter: actionFormatter({ dispatch }), // <-- pass dispatch
    align: 'right'
  }
]);

创建列配置对象并传递给表。

代码语言:javascript
复制
const config = { dispatch };

...

<BootstrapTable
  ref={table}
  bootstrap4
  keyField="_id"
  data={props.templates}
  columns={columns(config)} // <-- pass config to factory
  selectRow={selectRow(onSelect)}
  bordered={false}
  classes="table-dashboard table-striped table-sm fs--1 border-bottom border-200 mb-0 table-dashboard-th-nowrap"
  rowClasses="btn-reveal-trigger border-top border-200"
  headerClasses="bg-200 text-900 border-y border-200"
  {...paginationTableProps}
/>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67627778

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档