我有一个在ToolkitProvider中具有搜索功能的表组件(如下所示)
当我将搜索属性添加到ToolkitProvider中时,我的reducer会将原始状态作为空对象返回。当我从ToolkitProvider中删除搜索时,我的reducer将返回搜索正常工作所需的对象数组。我在想也许可以有条件地渲染toolkitProvider,但这似乎对我不起作用。有没有办法强制ToolkitProvider等到数据可用后才能使用其搜索功能?我正在使用react-bootstrap-table-next
同样,当search被添加到工具包提供程序时,我的reducer返回一个类似{ group:{}}的空对象,这给了我“数据属于object类型,预期的数组错误”如果我删除search和console.log(groupDetails),它会给我对象数组,表工作正常,添加search get empty object,删除search get array of objects。
下面是我的groupDetails缩减程序
import { GROUP_DETAILS_REQUEST, GROUP_DETAILS_FAIL, GROUP_DETAILS_SUCCESS } from "../actions/types"
export default function groupDetailsReducer ( state = { group: {} }, action ) {
switch(action.type) {
case GROUP_DETAILS_REQUEST:
return { loading: true }
case GROUP_DETAILS_SUCCESS:
return action.payload.data.contacts
case GROUP_DETAILS_FAIL:
return { loading: false, error: action.payload}
default:
return state
}
}下面是正在调用的后端userCtrl函数
const groupById = async (req, res) => {
try {
let group = await Group.findById(req.params.id).select('contacts').populate('contacts')
if(!group)
return res.status(400).json({error: "Group not found"})
res.json(group)
} catch(err) {
return res.status('400').json({
error: 'could not retrieve user'
})
}
}下面是使用react-bootstrap-table-next的前端组件
它很大……ToolkitProvider接近底部
import React, { createRef, useEffect, Fragment, useState, Suspense } from 'react';
import {
Button,
ButtonGroup,
Card,
CardBody,
Col,
DropdownItem,
DropdownMenu,
DropdownToggle,
Media,
Modal,
ModalBody,
ModalHeader,
Row,
UncontrolledDropdown
} from 'reactstrap';
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 ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import { FontAwesomeIcon , faSms} from '@fortawesome/react-fontawesome';
import { useSelector, useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import Flex from '../common/Flex';
import Avatar from '../common/Avatar';
import { getPaginationArray } from '../../helpers/utils';
import GroupContactChoose from './GroupContactChoose'
import { deleteGroup, deleteContact, groupById } from '../../actions/index';
const GroupEdit = ({match}) => {
const GroupId = match.params.id
let table = createRef();
const { SearchBar } = Search;
const [showContactModal, setShowContactModal ] = useState(false);
const [isSelected, setIsSelected] = useState(false);
const dispatch = useDispatch();
const groupDetails = useSelector((state) => state.groupDetails)
const { success: successGet } = groupDetails
const CustomTotal = ({ sizePerPage, totalSize, page, lastIndex }) => (
<span>
{(page - 1) * sizePerPage + 1} to {lastIndex > totalSize ? totalSize : lastIndex} of {totalSize} —{' '}
</span>
);
const handleDeleteGroup = (_id) => {
if(window.confirm("Are you sure?")) {
dispatch(deleteGroup(_id))}
}
const firstNameFormatter = (dataField, {_id, avatar, firstName}) => {
return (
<Link to={`/dashboard/contact/${_id}`}>
<Media tag={Flex} align="center">
<Avatar name={firstName} {...avatar} />
<Media body className="ml-2">
<h5 className="mb-0 fs--1">{firstName}</h5>
</Media>
</Media>
</Link>
);
};
const lastNameFormatter = (dataField, { _id, lastName }) => {
return (
<Link to={`/dashboard/contact/${_id}`}>
<Media tag={Flex} align="center">
<Media body className="ml-2">
<h5 className="mb-0 fs--1">{lastName}</h5>
</Media>
</Media>
</Link>
);
};
const actionFormatter = (dataField, { _id }, row) => (
// Control your row with this id
<UncontrolledDropdown>
<DropdownMenu right className="border py-2">
<DropdownItem onClick={() => console.log('Edit: ', _id)}>Edit</DropdownItem>
<DropdownItem onClick={() => { handleDeleteGroup(_id)} } className="text-danger">
Delete
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
);
const columns = [
{
dataField: 'firstName',
text: 'First Name',
headerClasses: 'border-0',
classes: 'border-0 py-2 align-middle',
formatter: firstNameFormatter,
sort: true
},
{
dataField: 'lastName',
text: 'Last Name',
headerClasses: 'border-0',
classes: 'border-0 py-2 align-middle',
formatter: lastNameFormatter,
sort: true
},
{
dataField: 'created',
headerClasses: 'border-0',
text: 'Created',
classes: 'border-0 py-2 align-middle',
sort: true,
align: 'right',
headerAlign: 'right'
},
{
dataField: 'actions',
headerClasses: 'border-0',
text: 'Actions',
classes: 'border-0 py-2 align-middle',
formatter: actionFormatter,
align: 'right'
}
];
const options = {
custom: true,
sizePerPage: 12,
totalSize: groupDetails?.length
useEffect(() => {
dispatch(groupById(GroupId))
}, [successGet])
console.log(groupDetails)
return (
<Card className="mb-3">
<FalconCardHeader title={groupDetails?.group?.data?.title} light={false}>
<Fragment>
<ButtonGroup className="mt-3">
<ButtonIcon icon="plus" onClick={() => { setShowContactModal(true)}}transform="shrink-3 down-2" color="falcon-default" size="sm" >
Add Contacts
</ButtonIcon>
<ButtonIcon icon="sms" onClick={() => { console.log(GroupId) }}transform="shrink-3 down-2" color="falcon-default" size="sm" >
Send SMS
</ButtonIcon>
<ButtonIcon icon="edit" onClick={() => { setShowContactModal(true)}}transform="shrink-3 down-2" color="falcon-default" size="sm" >
Edit
</ButtonIcon>
<ButtonIcon icon="trash" onClick={() => { setShowContactModal(true)}}transform="shrink-3 down-2" color="falcon-default" size="sm" >
Delete
</ButtonIcon>
<Modal isOpen={showContactModal} centered toggle={() => setShowContactModal(!showContactModal)}>
<ModalHeader className="text-center bg-light d-flex flex-between-center border-bottom-0">
How would you like to Import?
</ModalHeader>
<ModalBody className="p-0">
<Card>
<CardBody className="fs--1 font-weight-normal p-4">
<GroupContactChoose GroupId={GroupId} />
<Button block onClick={() => {setShowContactModal(false)}}>Close</Button>
</CardBody>
</Card>
</ModalBody>
</Modal>
<ButtonIcon icon="external-link-alt" transform="shrink-3 down-2" color="falcon-default" size="sm">
Export
</ButtonIcon>
</ButtonGroup>
</Fragment>
</FalconCardHeader>
<CardBody className="p-0">
{groupDetails.contacts ? (
<Card>
<CardBody>
...Loading // Attempting conditional rendering and having no luck..
</CardBody>
</Card>
) : (
<ToolkitProvider
keyField="_id"
columns={columns}
data={groupDetails}
bootstrap4
// search needs to be delayed returning an empty object?
search <---- when this is added to Toolkit Provider, my reducer returns an empty object that looks like {group: {}} , this gives me "data is of type object, expected array error" If I remove the search and console.log(groupDetails) It gives me the array of objects and the table works fine, Add search get empty object, remove search get array of objects.
>
{ props => (
<PaginationProvider pagination={paginationFactory(options)}>
{({ paginationProps, paginationTableProps }) => {
const lastIndex = paginationProps.page * paginationProps.sizePerPage;
return (
<Fragment>
<div className="table-responsive">
<SearchBar {...props.searchProps} />
<BootstrapTable
ref={table}
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}
{...props.baseProps}
/>
</div>
<Row noGutters className="px-1 py-3 flex-center">
<Col className="pl-3 fs--1">
<CustomTotal {...paginationProps} lastIndex={lastIndex} />
</Col>
<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>
)}
</ToolkitProvider>
)}
</CardBody>
</Card>
)
};
export default GroupEdit发布于 2021-08-02 22:39:49
听起来你不应该在你的reducer中使用group: {}作为你的默认状态(state = { group: {} })。
一开始你总是会得到默认状态,因为redux会触发一个初始化事件,而这个初始化事件不会影响到你的任何切换情况。
如果您立即加载,这可能是一个很好的初始状态:state = { group: {} }。
或者,考虑到错误,也可以使用空数组:state = []。
https://stackoverflow.com/questions/68628546
复制相似问题