React/Redux中API POST成功后如何触发GET请求更新JobsList?
Hey there! Let's break down how to fix this and get your JobsList updating after creating a new job. First, let's spot a few small issues in your existing code that might be causing confusion, then we'll tackle the main problem.
First, Fix the Tiny Typos & Inconsistencies
Before we solve the main issue, let's clean up some small mistakes that'll make your code work as expected:
- JobsList.js: You're using
teams.mapbut your prop is namedjobs— should bejobs.map. Also, your component is namedJobsListbut you're exportingJobsViewerat the end, that's a typo. - Action Type Mismatch: In JobsList you use
JOBS_LOADED, but your reducer listens forTEAMS_LOADED. Pick one name (likeJOBS_LOADEDto match your job-focused code) and make it consistent everywhere. - CreateJob.js: Your API call has a bug — you need to assign the request to a variable before awaiting it:
const request = api.Jobs.create(state);(also, no need to wrapstatein an extra object).
Solution 1: Dispatch a "Fetch Jobs" Action After Submission (Beginner-Friendly)
This is the most straightforward approach. We'll connect CreateJob to Redux (or use Redux Hooks) so it can trigger the same job-fetching logic that JobsList uses.
Option A: Using connect (Classic Redux)
Update CreateJob.js:
import React, { useState } from 'react'; import Button from '@material-ui/core/Button'; import TextField from '@material-ui/core/TextField'; import api from './Api'; import { connect } from 'react-redux'; import { JOBS_LOADED } from './ActionTypes'; const CreateJob = ({ refreshJobs }) => { const [state, setState] = useState({ jobName: '', creator: '' }); const handleInputChange = event => { setState({ ...state, [event.target.name]: event.target.value }); // validation stuff } const handleSubmit = async e => { e.preventDefault(); // Stop default form reload behavior try { await api.Jobs.create(state); // Trigger a refresh of the jobs list await refreshJobs(); // Reset the form setState({ jobName: '', creator: '' }); } catch (err) { console.error(err); } } return ( <div> <TextField name="jobName" value={state.jobName || ''} onChange={handleInputChange} /> <Button onClick={handleSubmit}>Create job</Button> </div> ); } const mapDispatchToProps = dispatch => ({ refreshJobs: async () => { const data = await api.Jobs.getAll(); dispatch({ type: JOBS_LOADED, payload: { data } }); } }); export default connect(null, mapDispatchToProps)(CreateJob);
Option B: Using Redux Hooks (Modern & Cleaner)
If you're using Redux v7.1+, use useDispatch for a simpler approach:
import React, { useState } from 'react'; import Button from '@material-ui/core/Button'; import TextField from '@material-ui/core/TextField'; import api from './Api'; import { useDispatch } from 'react-redux'; import { JOBS_LOADED } from './ActionTypes'; const CreateJob = () => { const dispatch = useDispatch(); const [state, setState] = useState({ jobName: '', creator: '' }); const handleInputChange = event => { setState({ ...state, [event.target.name]: event.target.value }); // validation stuff } const handleSubmit = async e => { e.preventDefault(); try { await api.Jobs.create(state); // Fetch and dispatch the latest jobs const data = await api.Jobs.getAll(); dispatch({ type: JOBS_LOADED, payload: { data } }); setState({ jobName: '', creator: '' }); } catch (err) { console.error(err); } } return ( <div> <TextField name="jobName" value={state.jobName || ''} onChange={handleInputChange} /> <Button onClick={handleSubmit}>Create job</Button> </div> ); } export default CreateJob;
Solution 2: Add the New Job Directly to Redux (More Efficient)
Instead of re-fetching all jobs (which is unnecessary), we can add the newly created job directly to our Redux store. This saves an API call and is faster.
Add a new action type:
// ActionTypes.js export const JOBS_LOADED = 'JOBS_LOADED'; export const JOB_ADDED = 'JOB_ADDED';Update the reducer to handle the new action:
// JobsReducer.js import { JOBS_LOADED, JOB_ADDED } from './ActionTypes'; export default (state = {teams: []}, action) => { switch (action.type) { case JOBS_LOADED: return { ...state, teams: action.payload.data, }; case JOB_ADDED: // Add the new job to the existing list return { ...state, teams: [...state.teams, action.payload.job], }; default: return state; } };Dispatch the new action in CreateJob:
const handleSubmit = async e => { e.preventDefault(); try { // Assume your API returns the full created job (with jobId and other backend-generated fields) const newJob = await api.Jobs.create(state); // Dispatch the action to add the job to the store dispatch({ type: JOB_ADDED, payload: { job: newJob } }); setState({ jobName: '', creator: '' }); } catch (err) { console.error(err); } }
Final Notes
- Naming Consistency: I'd recommend renaming
teamstojobsin your reducer (since your app is job-focused) — it'll make your code easier to follow. - Choose the Right Solution: Solution 1 is great for beginners because it's simple and relies on logic you already have. Solution 2 is better for performance, especially if your job list gets large.
内容的提问来源于stack exchange,提问作者Jose the hose

