TypeError: Cannot read properties of undefined (reading 'rejectWithValue') - Redux Toolkit
TypeError: Cannot read properties of undefined (reading 'rejectWithValue') - Redux Toolkit
我正在构建一个具有基本 crud 操作的全栈 mern 应用程序。到目前为止,我已经完成了后端 rest api 并在邮递员中进行了测试,所有端点在这里都可以正常工作。在前端,我可以创建潜在客户、删除潜在客户并查看潜在客户,但是,当尝试更新潜在客户时,我收到一个打字错误,提示“无法读取未定义的属性(读取 'rejectWithValue')”。我似乎能理解手头的问题。
leadService.js
import axios from "axios";
const API_URL = "/api/leads";
// Create new lead
const createLead = async (leadData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.post(API_URL, leadData, config);
return response.data;
};
// Get user leads
const getLeads = async (token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.get(API_URL, config);
return response.data;
};
// Get single lead
const getSingleLead = async (id, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.get(API_URL + `/${id}`, config);
return response.data;
};
// Delete user lead
const deleteLead = async (leadId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.delete(API_URL + "/" + leadId, config);
return response.data;
};
// Update lead
const updateLead = async (leadId, leadData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.put(API_URL + "/" + leadId, leadData, config);
return response.data;
};
const leadService = {
createLead,
getLeads,
deleteLead,
getSingleLead,
updateLead,
};
export default leadService;
leadSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import leadService from "./leadService";
const initialState = {
leads: [],
lead: [],
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Create new lead
export const createLead = createAsyncThunk(
"leads/create",
async (leadData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.createLead(leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Get user lead
export const getLeads = createAsyncThunk(
"leads/getAll",
async (_, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.getLeads(token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// get single user lead
export const getSingleLead = createAsyncThunk(
"leads/getSingle",
async (id, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.getSingleLead(id, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Delete user lead
export const deleteLead = createAsyncThunk(
"leads/delete",
async (id, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.deleteLead(id, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Update lead
export const updateLead = createAsyncThunk(
"leads/update",
async (leadId, leadData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.updateLead(leadId, leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const leadSlice = createSlice({
name: "lead",
initialState,
reducers: {
reset: (state) => initialState,
clear: (state) => {
state.isSuccess = false;
state.isError = false;
},
filterSearchResults: (state, action) => {
state.leads = state.leads.filter(
(lead) =>
lead.company_name
.toLowerCase()
.includes(action.payload.toLowerCase()) && lead
);
},
},
extraReducers: (builder) => {
builder
.addCase(createLead.pending, (state) => {
state.isLoading = true;
state.message = "";
state.isError = false;
state.isSuccess = false;
})
.addCase(createLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads.unshift(action.payload);
})
.addCase(createLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getLeads.pending, (state) => {
state.isLoading = true;
})
.addCase(getLeads.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = action.payload;
})
.addCase(getLeads.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getSingleLead.pending, (state) => {
state.isLoading = true;
})
.addCase(getSingleLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.lead = action.payload;
})
.addCase(getSingleLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(deleteLead.pending, (state) => {
state.isLoading = true;
})
.addCase(deleteLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = state.leads.filter(
(lead) => lead._id !== action.payload.id
);
})
.addCase(deleteLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(updateLead.pending, (state) => {
state.isLoading = true;
})
.addCase(updateLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = state.leads.map((lead) =>
lead._id !== action.payload.id
? {
...lead,
company_name: action.payload.company_name,
first_name: action.payload.first_name,
last_name: action.payload.last_name,
email: action.payload.email,
position: action.payload.position,
website: action.payload.website,
notes: action.payload.notes,
status: action.payload.status,
}
: lead
);
})
.addCase(updateLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
});
},
});
export const { reset, clear, filterSearchResults } = leadSlice.actions;
export default leadSlice.reducer;
EditForm.js
import React, { useEffect, useState } from "react";
import Button from "@mui/material/Button";
import ClearIcon from "@mui/icons-material/Clear";
import { useDispatch } from "react-redux";
import { resetModal } from "../../features/modal/modalSlice";
import { updateLead } from "../../features/leads/leadSlice";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
function EditForm() {
const { isError, isSuccess, lead, message } = useSelector(
(state) => state.lead
);
const [leadData, setLeadData] = useState({
company_name: lead.company_name,
first_name: lead.first_name,
last_name: lead.last_name,
email: lead.email,
position: lead.position,
website: lead.website,
notes: lead.notes,
status: lead.status,
});
const {
company_name,
first_name,
last_name,
email,
position,
website,
notes,
status,
} = leadData;
const dispatch = useDispatch();
const navigate = useNavigate();
useEffect(() => {
if (isError) {
toast.error("Lead not updated");
dispatch(resetModal());
}
if (isSuccess) {
toast.success("Lead updated");
dispatch(resetModal());
navigate();
}
});
const handleClick = () => {
dispatch(resetModal());
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateLead(lead._id, leadData));
};
const onChange = (e) => {
setLeadData((prevState) => ({
...prevState,
[e.target.name]: e.target.value,
}));
};
return (
<div className="form">
<ClearIcon
sx={{ float: "right", cursor: "pointer" }}
onClick={handleClick}
/>
<h1 className="form__header">Edit Lead</h1>
<form className="form__container" onSubmit={handleSubmit}>
<label>Company Name</label>
<input
type="text"
name="company_name"
onChange={onChange}
className="form__input"
value={company_name}
/>
<label>First Name</label>
<input
type="text"
name="first_name"
onChange={onChange}
className="form__input"
value={first_name}
/>
<label>Last Name</label>
<input
type="text"
name="last_name"
onChange={onChange}
className="form__input"
value={last_name}
/>
<label>Email</label>
<input
type="email"
name="email"
onChange={onChange}
className="form__input"
value={email}
/>
<label>Position</label>
<input
type="text"
name="position"
onChange={onChange}
className="form__input"
value={position}
/>
<label>Website</label>
<input
type="text"
name="website"
onChange={onChange}
className="form__input"
value={website}
/>
<label>Notes</label>
<textarea
name="notes"
onChange={onChange}
className="form__input form__textarea"
value={notes}
/>
<label>Status</label>
<input
type="text"
name="status"
onChange={onChange}
className="form__input"
value={status}
/>
<Button
size="large"
type="submit"
id={lead._id}
sx={{
color: "#fff",
background: "var(--primary)",
textTransform: "initial",
fontWeight: "initial",
border: "none",
"&:hover": {
backgroundColor: "var(--primary)",
border: "none",
},
}}
variant="outlined"
>
Submit
</Button>
</form>
</div>
);
}
export default EditForm;
您可以使用对象作为参数并解构它。
export const updateLead = createAsyncThunk(
"leads/update",
async ({leadId, leadData}, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.updateLead(leadId, leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateLead({leadId: lead._id, leadData}));
};
我正在构建一个具有基本 crud 操作的全栈 mern 应用程序。到目前为止,我已经完成了后端 rest api 并在邮递员中进行了测试,所有端点在这里都可以正常工作。在前端,我可以创建潜在客户、删除潜在客户并查看潜在客户,但是,当尝试更新潜在客户时,我收到一个打字错误,提示“无法读取未定义的属性(读取 'rejectWithValue')”。我似乎能理解手头的问题。
leadService.js
import axios from "axios";
const API_URL = "/api/leads";
// Create new lead
const createLead = async (leadData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.post(API_URL, leadData, config);
return response.data;
};
// Get user leads
const getLeads = async (token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.get(API_URL, config);
return response.data;
};
// Get single lead
const getSingleLead = async (id, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.get(API_URL + `/${id}`, config);
return response.data;
};
// Delete user lead
const deleteLead = async (leadId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.delete(API_URL + "/" + leadId, config);
return response.data;
};
// Update lead
const updateLead = async (leadId, leadData, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
};
const response = await axios.put(API_URL + "/" + leadId, leadData, config);
return response.data;
};
const leadService = {
createLead,
getLeads,
deleteLead,
getSingleLead,
updateLead,
};
export default leadService;
leadSlice.js
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import leadService from "./leadService";
const initialState = {
leads: [],
lead: [],
isError: false,
isSuccess: false,
isLoading: false,
message: "",
};
// Create new lead
export const createLead = createAsyncThunk(
"leads/create",
async (leadData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.createLead(leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Get user lead
export const getLeads = createAsyncThunk(
"leads/getAll",
async (_, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.getLeads(token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// get single user lead
export const getSingleLead = createAsyncThunk(
"leads/getSingle",
async (id, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.getSingleLead(id, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Delete user lead
export const deleteLead = createAsyncThunk(
"leads/delete",
async (id, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.deleteLead(id, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
// Update lead
export const updateLead = createAsyncThunk(
"leads/update",
async (leadId, leadData, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.updateLead(leadId, leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
export const leadSlice = createSlice({
name: "lead",
initialState,
reducers: {
reset: (state) => initialState,
clear: (state) => {
state.isSuccess = false;
state.isError = false;
},
filterSearchResults: (state, action) => {
state.leads = state.leads.filter(
(lead) =>
lead.company_name
.toLowerCase()
.includes(action.payload.toLowerCase()) && lead
);
},
},
extraReducers: (builder) => {
builder
.addCase(createLead.pending, (state) => {
state.isLoading = true;
state.message = "";
state.isError = false;
state.isSuccess = false;
})
.addCase(createLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads.unshift(action.payload);
})
.addCase(createLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getLeads.pending, (state) => {
state.isLoading = true;
})
.addCase(getLeads.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = action.payload;
})
.addCase(getLeads.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(getSingleLead.pending, (state) => {
state.isLoading = true;
})
.addCase(getSingleLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.lead = action.payload;
})
.addCase(getSingleLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(deleteLead.pending, (state) => {
state.isLoading = true;
})
.addCase(deleteLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = state.leads.filter(
(lead) => lead._id !== action.payload.id
);
})
.addCase(deleteLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
.addCase(updateLead.pending, (state) => {
state.isLoading = true;
})
.addCase(updateLead.fulfilled, (state, action) => {
state.isLoading = false;
state.isSuccess = true;
state.leads = state.leads.map((lead) =>
lead._id !== action.payload.id
? {
...lead,
company_name: action.payload.company_name,
first_name: action.payload.first_name,
last_name: action.payload.last_name,
email: action.payload.email,
position: action.payload.position,
website: action.payload.website,
notes: action.payload.notes,
status: action.payload.status,
}
: lead
);
})
.addCase(updateLead.rejected, (state, action) => {
state.isLoading = false;
state.isError = true;
state.message = action.payload;
});
},
});
export const { reset, clear, filterSearchResults } = leadSlice.actions;
export default leadSlice.reducer;
EditForm.js
import React, { useEffect, useState } from "react";
import Button from "@mui/material/Button";
import ClearIcon from "@mui/icons-material/Clear";
import { useDispatch } from "react-redux";
import { resetModal } from "../../features/modal/modalSlice";
import { updateLead } from "../../features/leads/leadSlice";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import { useSelector } from "react-redux";
function EditForm() {
const { isError, isSuccess, lead, message } = useSelector(
(state) => state.lead
);
const [leadData, setLeadData] = useState({
company_name: lead.company_name,
first_name: lead.first_name,
last_name: lead.last_name,
email: lead.email,
position: lead.position,
website: lead.website,
notes: lead.notes,
status: lead.status,
});
const {
company_name,
first_name,
last_name,
email,
position,
website,
notes,
status,
} = leadData;
const dispatch = useDispatch();
const navigate = useNavigate();
useEffect(() => {
if (isError) {
toast.error("Lead not updated");
dispatch(resetModal());
}
if (isSuccess) {
toast.success("Lead updated");
dispatch(resetModal());
navigate();
}
});
const handleClick = () => {
dispatch(resetModal());
};
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateLead(lead._id, leadData));
};
const onChange = (e) => {
setLeadData((prevState) => ({
...prevState,
[e.target.name]: e.target.value,
}));
};
return (
<div className="form">
<ClearIcon
sx={{ float: "right", cursor: "pointer" }}
onClick={handleClick}
/>
<h1 className="form__header">Edit Lead</h1>
<form className="form__container" onSubmit={handleSubmit}>
<label>Company Name</label>
<input
type="text"
name="company_name"
onChange={onChange}
className="form__input"
value={company_name}
/>
<label>First Name</label>
<input
type="text"
name="first_name"
onChange={onChange}
className="form__input"
value={first_name}
/>
<label>Last Name</label>
<input
type="text"
name="last_name"
onChange={onChange}
className="form__input"
value={last_name}
/>
<label>Email</label>
<input
type="email"
name="email"
onChange={onChange}
className="form__input"
value={email}
/>
<label>Position</label>
<input
type="text"
name="position"
onChange={onChange}
className="form__input"
value={position}
/>
<label>Website</label>
<input
type="text"
name="website"
onChange={onChange}
className="form__input"
value={website}
/>
<label>Notes</label>
<textarea
name="notes"
onChange={onChange}
className="form__input form__textarea"
value={notes}
/>
<label>Status</label>
<input
type="text"
name="status"
onChange={onChange}
className="form__input"
value={status}
/>
<Button
size="large"
type="submit"
id={lead._id}
sx={{
color: "#fff",
background: "var(--primary)",
textTransform: "initial",
fontWeight: "initial",
border: "none",
"&:hover": {
backgroundColor: "var(--primary)",
border: "none",
},
}}
variant="outlined"
>
Submit
</Button>
</form>
</div>
);
}
export default EditForm;
您可以使用对象作为参数并解构它。
export const updateLead = createAsyncThunk(
"leads/update",
async ({leadId, leadData}, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.token;
return await leadService.updateLead(leadId, leadData, token);
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
return thunkAPI.rejectWithValue(message);
}
}
);
const handleSubmit = (e) => {
e.preventDefault();
dispatch(updateLead({leadId: lead._id, leadData}));
};