我正在尝试让一个功能组件在对象中的一个值更改后重新渲染:
所以项目有任务:项目任务和project.completed_tasks
每个任务也是一个对象,其属性is_completed:task.is_completed
一旦is_completed更改为真或假,我希望项目组件使用任务的更新进度重新渲染。
这适用于后端,但我无法让它与 React 和钩子 API 一起使用。我猜这与浅比较与深度比较有关,但我已经在任务上下文中的updateTask函数中创建了一个副本。
任何帮助将不胜感激!粗体,以便更容易阅读,因为它很多。
这是我想要更改的组件:
const Project = ({project, formatDate}) => {
const tasksContext = useContext(TasksContext);
const {tasksCompleted} = tasksContext;
const [open, setOpen] = useState(false);
const [progress] = useState(tasksCompleted.filter(task => task.project_id === project.id).length);
return (
<Card.Content>
<Card.Header>
{project.name}
</Card.Header>
<Card.Meta>
{formatDate(project.start_date)} - {formatDate(project.end_date)}
</Card.Meta>
<Card.Description>
<Progress value={progress} total={project.total_tasks} progress='ratio' warning/>
</Card.Description>
</Card.Content>
<Card.Content extra>
<List celled horizontal size="mini" floated="right">
<List.Item as="a" onClick={handleEdit}>Edit</List.Item>
<List.Item as="a" onClick={handleDelete}>Delete</List.Item>
</List>
<Confirm
open={open}
onCancel={handleCancel}
onConfirm={handleConfirm}
cancelButton='Never mind'
confirmButton="Let's do it"
size='mini'
/>
</Card.Content>
)
};
这是我的任务上下文钩子:
import React, {createContext, useState} from 'react';
import PropTypes from "prop-types";
export const TasksContext = createContext({});
export const TasksProvider = props => {
//initial values obtained from props
const {
tasks: initialTasks,
tasksCompleted: initialTasksCompleted,
children
} = props;
//state to keep the values
const [tasks, setTasks] = useState(initialTasks);
const [tasksCompleted, setTasksCompleted] = useState(initialTasksCompleted);
//============== TASK FUNCTIONS ===================//
const getTasks = () => {
const token = localStorage.getItem('token');
const getObj = {
'method': 'GET',
'headers': {
'Authorization': `Bearer ${token}`
}
}
const tasksUrl = `http://localhost:3000/tasks`;
fetch(tasksUrl, getObj)
.then(res => res.json())
.then(tasks => {
setTasks(tasks)
getTasksCompleted(tasks)
})
}
const getTasksCompleted = (tasks) => {
const completedTasks = tasks.filter(task => task.is_completed === true);
setTasksCompleted(completedTasks);
}
const updateTask = (task) => {
const updatedTasks = [...tasks];
const index = updatedTasks.findIndex(taskToUpdate => taskToUpdate.id === task.id);
updatedTasks[index] = task;
setTasks(updatedTasks);
getTasksCompleted(updatedTasks);
}
//make the context object
const tasksContext = {
tasks,
setTasks,
tasksCompleted,
getTasks,
updateTask
};
return <TasksContext.Provider value={tasksContext}>{children}</TasksContext.Provider>
};
export const {TasksConsumer} = TasksContext;
TasksProvider.propTypes = {
tasks: PropTypes.array,
tasksCompleted: PropTypes.array
};
TasksProvider.defaultProps = {
tasks: [],
tasksCompleted: []
};
下面是调用 updateTask 函数的另一个组件:
const Task = ({task}) => {
const tasksContext = useContext(TasksContext);
const {updateTask} = tasksContext;
const [name, setName] = useState(task.name);
const [checked, setChecked] = useState(task.is_completed);
const [editing, setEditing] = useState(task.name ? false : true);
const editTask = (name, is_completed) => {
const taskUrl = `http://localhost:3000/tasks/${task.id}`
const token = localStorage.getItem('token')
const taskObj = {
'method': 'PATCH',
'headers': {
"Accept": "application/json",
'Authorization': `Bearer ${token}`,
"Content-Type": "application/json"
},
'body': JSON.stringify({name, is_completed})
}
fetch(taskUrl, taskObj)
.then(res => res.json())
.then(task => {
setName(name);
updateTask(task);
})
}
...render function etc
我认为问题在于您如何跟踪项目组件中的进度:
const [progress] = useState(tasksCompleted.filter(task => task.project_id === project.id).length);
此行仅初始化progress
的值。如果希望组件重新呈现,则需要在tasksCompleted
更改后更改进度值。假设tasksCompleted
正确更改,您可以使用useEffect
监视变量并更新progress
状态。
const [progress, setProgress] = useState(tasksCompleted.filter(task => task.project_id === project.id).length);
useEffect(() => {
setProgress(tasksCompleted.filter(task => task.project_id === project.id).length)
}, [tasksCompleted])
useEffect 中指定的函数将在第一次呈现时运行,并且每次数组中的值更改时都会运行。由于它会更新状态,因此它还将触发重新渲染。
尝试在功能组件中这样useEffect()
:
const tasksContext = useContext(TasksContext);
useEffect(() => {
tasksContext
}, [...Object.values(tasksContext]);
这将查找值本身的变化,并应在适当的时间触发useContext()
。