无法使用 Redux/RTK 从 MERN CRUD 应用程序中的 MUI DataGrid 中删除行?



对于我的生活,我不明白为什么我不能让删除按钮在这个材料UI (MUI V5)数据网格表上工作。我对编程有点陌生,尤其是使用MERN和Redux,所以我的大脑现在很紧张,整个周末我尝试了无数的东西,包括Google, Stack Overflow,还有长时间的休息。下面的代码是我认为它应该如何工作的,但是当按钮被点击时,前端什么也没有发生。据称,删除请求已成功发送到服务器(或完成),但当然实际上并没有从数据库中删除JSON记录,并且我使用redux开发工具在控制台中获得此响应消息:

转换为objecd失败,值"未定义";(类型字符串)在路径"_id"为型号";&;

创建或添加项目在单独的路由上的单独表单的前端工作得很好。当我在构建前端之前在Postman中测试Delete时,它工作得很好。答案可能很简单,我只是没有经验,想不出来。这是一个简单的JS问题与对象变量,我没有看到(似乎从错误消息)或可能是一个状态管理/redux问题?它可能与MongoDB的默认"_id"属性与MUI相互作用?或者完全是别的什么?下面是数据网格组件:

import React, { useState, useEffect } from 'react'
import { DataGrid, GridToolbar } from '@mui/x-data-grid'
import {getPurchases} from '../features/purchases/purchaseSlice'
import {useSelector, useDispatch} from 'react-redux'
import { Button } from '@mui/material'
import {deletePurchase} from '../features/purchases/purchaseSlice'
const TableForm = () => {
const [pageSize, setPageSize] = useState(10);

const dispatch = useDispatch()
const {purchase, purchases, isError, message} = useSelector((state) => state.purchases)
useEffect(() => {
if (isError) {
console.log(message);
}
dispatch(getPurchases());
}, [isError, dispatch, message]);
const renderDetailsButton = () => {
return (
<strong>
<Button
className="delete"
variant="contained"
color="primary"
size="small"
style={{ margin: 0}}
onClick={() => {dispatch(deletePurchase(purchases.id))}}
>
X           
</Button>
</strong>
)
}

const columns = [
{field: '_id', headerName: 'ID', sortable: 'false', filterable: 'false', disableColumnMenu: 'true', visibility: 'false'},
{field: 'title', headerName: 'Title', editable: true},
{field: 'producer', headerName: 'Producer'},
{field: 'director', headerName: 'Director'},
{field: 'platform', headerName: 'Platform'},
{field: 'year', headerName: 'Year of Release', maxwidth: 75},
{field: 'price', headerName: 'Price', maxwidth: 75},
{field: 'length', maxwidth: 75},
{field: 'requesterName', headerName: 'Requester Name'},
{field: 'requesterEmail', headerName: 'Requester Email'},
{field: 'requesterDepartment', headerName: 'Requester Department'},
{field: 'notes', headerName: 'Notes/Comments'},
{field: 'createdAt', headerName: 'Created On', type: 'date' },
{
field: 'col5',
headerName: 'Edit',
width: 150,
renderCell: renderDetailsButton,
disableClickEventBubbling: true,
},
/*{
field: 'col6',
headerName: 'Delete',
width: 150,
renderCell: renderDetailsButton,
disableClickEventBubbling: true,
},*/
];

return (
<div style={{ height: 700, width: '100%' }}>
<DataGrid experimentalFeatures={{ newEditingApi: true }} getRowId={row => row._id}
sx={{
boxShadow: 1,
border: 1,
borderColor: 'lightgrey',
'& .MuiDataGrid-cell:hover': {
color: 'primary.main',
},
}}
initialState={{
columns:{
columnVisibilityModel: {_id: false}
},
pagination: {
pageSize: 10,
},
}}
rows={purchases}
columns= {columns}
components={{Toolbar: GridToolbar}}
pageSize={pageSize}
onPageSizeChange={(newPageSize) => setPageSize(newPageSize)}
rowsPerPageOptions={[10, 25, 50, 100]}
/>
</div>
)
}
export default TableForm

片:

import {createSlice, createAsyncThunk} from '@reduxjs/toolkit'
import purchaseService from './purchaseService'

const initialState = {
purchases: [],
isError: false,
isSuccess: false,
isLoading: false,
message: ''
}
//Create new Purchase
export const createPurchase = createAsyncThunk(
'purchases/create', 
async (purchaseData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await purchaseService.createPurchase(purchaseData, token)
} catch (error) {
const message =
(error.response && 
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
})
//Get purchases
export const getPurchases = createAsyncThunk('purchases/getAll', async(_, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await purchaseService.getPurchases(token)
} catch (error) {
const message =
(error.response && 
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
})
//Delete Purchase
export const deletePurchase = createAsyncThunk(
'purchases/delete', 
async (id, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token
return await purchaseService.deletePurchase(id, token)
} catch (error) {
const message =
(error.response && 
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
})
export const purchaseSlice = createSlice({
name: 'purchase',
initialState,
reducers: {
reset: (state) => initialState,
},
extraReducers: (builder) => {
builder
.addCase(createPurchase.pending, (state) => {
state.isLoading = true
})
.addCase(createPurchase.fulfilled, (state, action) => {
state.isLoading = false 
state.isSuccess = true
state.purchases.push(action.payload)
})
.addCase(createPurchase.rejected, (state, action) => {
state.isLoading = false 
state.isError = true
state.message = action.payload
})
.addCase(getPurchases.pending, (state) => {
state.isLoading = true
})
.addCase(getPurchases.fulfilled, (state, action) => {
state.isLoading = false 
state.isSuccess = true
state.purchases = action.payload
})
.addCase(getPurchases.rejected, (state, action) => {
state.isLoading = false 
state.isError = true
state.message = action.payload
})
.addCase(deletePurchase.pending, (state) => {
state.isLoading = true
})
.addCase(deletePurchase.fulfilled, (state, action) => {
state.isLoading = false 
state.isSuccess = true
state.purchases = state.purchases.filter((purchases) => purchases._id !== action.payload.id)})
.addCase(deletePurchase.rejected, (state, action) => {
state.isLoading = false 
state.isError = true
state.message = action.payload
})
}
})
export const {reset} = purchaseSlice.actions
export default purchaseSlice.reducer

片服务:


const API_URL = '/api/purchases/';
//Create new Purchase
const createPurchase = async (purchaseData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`
}
}
const response = await axios.post(API_URL, purchaseData, config)
return response.data
}

//Get purchases
const getPurchases = async (token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`
}
}
const response = await axios.get(API_URL, config)
return response.data
}
//Delete Purchase
const deletePurchase = async (purchaseId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`
}
}
const response = await axios.delete(API_URL + purchaseId, config)
return response.data
}
const purchaseService = {
createPurchase,
getPurchases,
deletePurchase,
}
export default purchaseService

数据网格组件的页面/路由是打开的,以防万一

import {useEffect} from 'react'
import {useNavigate} from 'react-router-dom'
import {useSelector} from 'react-redux'
import TableForm from '../components/tableForm'
import '../index.css'
import Spinner from '../components/Spinner'

function Table() {
const {user} = useSelector((state) => state.auth)
let navigate = useNavigate();
const {isLoading, isError, message} = useSelector((state) => state.purchases)
useEffect(() => {
if (isError) {
console.log(message);
}
if (!user) {
navigate('/login')
}

}, [user, navigate, isError, message] )
return (
<>
<div className='heading'>
<h1>License Table</h1>
</div>

<TableForm/>
</>
)
}
export default Table

所以,我为其他可能偶然遇到这个问题的人想出了解决方案。RenderDetailsButton应该像下面这样传递id。

const renderDetailsButton = (id) => {
return (
<strong>
<Button
className="delete"
variant="contained"
color="primary"
size="small"
style={{ margin: 0 }}
onClick={() => { dispatch(deletePurchase(id))}}
>
X
</Button>
</strong>
)
}

最新更新