尝试更新组件时,它在数据库中成功更新,但状态未更新。
Home.js
import { useEffect } from "react"
import { useWorkoutsContext } from '../hooks/useWorkoutsContext'
// components
import WorkoutDetails from '../components/WorkoutDetails'
import WorkoutForm from "../components/WorkoutForm"
const Home = () => {
const { workouts, dispatch } = useWorkoutsContext()
useEffect(() => {
const fetchWorkouts = async () => {
try {
const response = await fetch('/api/workouts')
if (!response.ok) {
throw new Error('Network response was not okay')
}
const json = await response.json()
dispatch({ type: 'SET_WORKOUTS', payload: json })
} catch (error) {
console.log('Error fetching workouts: ', error)
}
}
fetchWorkouts()
}, [dispatch])
const handleUpdateSubmit = (updatedWorkoutData) => {
console.log(updatedWorkoutData)
// Update the local state with the updated workout
const updatedWorkouts = workouts.map((workout) =>
workout._id === updatedWorkoutData._id ? updatedWorkoutData : workout,
);
dispatch({ type: 'SET_WORKOUTS', payload: updatedWorkouts });
}
return (
<div className="home">
<div className="workouts">
{workouts &&
workouts.map((workout) => (
<WorkoutDetails
key={workout._id}
workout={workout}
onUpdate={handleUpdateSubmit} // Pass the update handler to WorkoutDetails
/>
))}
</div>
<WorkoutForm />
</div>
)
}
export default Home
锻炼详情.js
import { useWorkoutsContext } from '../hooks/useWorkoutsContext'
import React, { useState } from 'react';
// date fns
import formatDistanceToNow from 'date-fns/formatDistanceToNow'
const WorkoutDetails = ({ workout }) => {
const { dispatch } = useWorkoutsContext()
const [isUpdating, setIsUpdating] = useState(false);
const [updatedWorkout, setUpdatedWorkout] = useState({
title: workout.title,
load: workout.load,
reps: workout.reps
})
const handleDeleteClick = async () => {
const response = await fetch('/api/workouts/' + workout._id, {
method: 'DELETE'
})
const json = await response.json()
if (response.ok) {
dispatch({type: 'DELETE_WORKOUT', payload: json})
}
}
const handleUpdateClick = () => {
setIsUpdating(true);
};
const handleInputChange = (e) => {
const { name, value } = e.target
setUpdatedWorkout({ ...updatedWorkout, [name]: value })
}
const handleUpdateSubmit = async (e) => {
e.preventDefault();
try {
const response = await fetch('/api/workouts/' + workout._id, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(updatedWorkout),
});
if (!response.ok) {
throw new Error('Network response was not okay');
}
const json = await response.json();
setIsUpdating(false);
dispatch({ type: 'UPDATE_WORKOUT', payload: json });
} catch (error) {
console.log('Error updating workout: ', error);
}
};
return (
<div className="workout-details">
<h4>{workout.title}</h4>
<p><strong>Load: </strong>{workout.load}</p>
<p><strong>Reps: </strong>{workout.reps}</p>
{isUpdating ? (
<form onSubmit={handleUpdateSubmit}>
<label htmlFor="title">Title:</label>
<input
type="text"
id="title"
name="title"
value={updatedWorkout.title}
onChange={handleInputChange}
/>
<label htmlFor="load">Load:</label>
<input
type="text"
id="load"
name="load"
value={updatedWorkout.load}
onChange={handleInputChange}
/>
<label htmlFor="reps">Reps:</label>
<input
type="text"
id="reps"
name="reps"
value={updatedWorkout.reps}
onChange={handleInputChange}
/>
<button type="submit">Update Workout</button>
</form>
) : (
<>
<p>{formatDistanceToNow(new Date(workout.createdAt), { addSuffix: true })}</p>
<span className='material-symbols-outlined' onClick={handleDeleteClick}>delete</span>
<button className='update-btn' onClick={handleUpdateClick}>Update</button>
</>
)}
</div>
)
}
export default WorkoutDetails
WorkoutContext.js
import { createContext, useReducer } from "react";
export const WorkoutContext = createContext()
export const workoutsReducer = (state, action) => {
switch (action.type) {
case 'SET_WORKOUTS':
return {
workouts: action.payload
}
case 'CREATE_WORKOUT':
return {
workouts: [action.payload, ...state.workouts]
}
case 'DELETE_WORKOUT':
return {
workouts: state.workouts.filter((w) => w._id !== action.payload._id)
}
case 'UPDATE_WORKOUT':
return {
...state,
workouts: state.workouts.map((workout) =>
workout._id === action.payload._id ? action.payload : workout
),
}
default:
return state
}
}
export const WorkoutsContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(workoutsReducer, {
workouts: null
})
return (
<WorkoutContext.Provider value={{...state, dispatch}}>
{ children }
</WorkoutContext.Provider>
)
}
useWorkoutsContext.js
import { WorkoutContext } from "../context/WorkoutContext";
import { useContext } from "react";
export const useWorkoutsContext = () => {
const context = useContext(WorkoutContext)
if (!context) {
throw Error('useWorkoutsContext must be inside an WorkoutsContectProvider')
}
return context
}
如果需要,很高兴提供更多我的代码!
谢谢!
我尝试创建一个名为“handleUpdateSubmit”的道具来在更新组件时更新组件的状态。但是,更新的唯一方法是通过手动刷新。
您似乎已经设置了一个上下文和减速器来管理您的锻炼状态,这是一个很好的方法。从您的代码来看,更新该状态下的锻炼的逻辑似乎是正确的。
该问题可能与您如何将 onUpdate 属性传递给 WorkoutDetails 组件有关。让我们仔细检查一些事情:
在 Home.js 中,确保正确传递 onUpdate 属性:
{workouts &&
workouts.map((workout) => (
<WorkoutDetails
key={workout._id}
workout={workout}
onUpdate={handleUpdateSubmit} // Pass the update handler to WorkoutDetails
/>
))}
在 WorkoutDetails.js 中,使用 onUpdate 属性来触发更新:
const WorkoutDetails = ({ workout, onUpdate }) => {
// ...
const handleUpdateSubmit = async (e) => {
e.preventDefault();
try {
// ... (your update logic)
// Call the onUpdate function passed from Home.js
onUpdate(updatedWorkoutData);
setIsUpdating(false);
} catch (error) {
console.log('Error updating workout: ', error);
}
};
// ...
}
确保更新成功后正确调用onUpdate。如果一切设置正确,更新状态应该可以工作。