我不明白为什么这些格式化程序函数被放置在名为TemplateTable的主组件之外。
例如,如果您需要使用actionformatter,您不能传递一个分派函数,对吗?
我遇到了一个问题,试图将删除按钮的actionformatter设置为调度(deleteTemplate())。
当操作格式化程序在主组件TemplateTable之外运行代码时,我得到的分派是未定义的。当我在组件中定义分派时,我显然得到了不能使用react的函数组件问题。
我只需在templateTable块中包含actionformatter,就可以解决整个问题。我只是觉得自己很简单,想知道是否有人对此有任何意见。
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);发布于 2021-05-20 22:54:17
简单的回答是,对于消费组件不存在任何依赖,因此从TemplateTable组件中将这些声明具体化是完全合理的。
虽然您可以将代码移回组件中,以关闭功能组件主体的附件中的任何依赖项,但我认为我们可以做得更好。
我建议将dispatch函数运行到任何需要它的特定格式化程序,即
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转换为工厂函数,以便接收和传递配置,即
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'
}
]);创建列配置对象并传递给表。
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}
/>https://stackoverflow.com/questions/67627778
复制相似问题