簡體   English   中英

在另一個 object 內的值發生變化后,React 會更新組件 - 怎么辦?

[英]React hooks updating component after value inside object inside another object changes - how to?

我試圖讓一個功能組件在 object 中的一個值發生更改后重新呈現 object:

所以項目有任務: project.tasksproject.completed_tasks

每個任務也是一個 object,它有一個屬性 is_completed: task.is_completed

一旦 is_completed 更改為 true 或 false,我希望Project comp.net 重新呈現任務的更新進度。

這在后端工作,但我無法讓它與 React 一起工作,並掛鈎 api。我猜它與淺比較與深度比較有關,但我已經在 tasksContext 的updateTask function 中創建了一個副本。

任何幫助,將不勝感激。 加粗以便更容易閱讀,因為它很多。

這是我要更改的組件:

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>
    )
};

這是我的 tasksContext 掛鈎:

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 function 的另一個組件:

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

在您的功能組件中像這樣嘗試useEffect()

const tasksContext = useContext(TasksContext);

useEffect(() => {
    tasksContext
}, [...Object.values(tasksContext]);

這將查找值本身的變化,並應在適當的時間觸發useContext()

我認為問題在於您如何跟蹤項目組件的進度:

const [progress] = useState(tasksCompleted.filter(task => task.project_id === project.id).length);

此行僅初始化progress的值。 如果您希望組件重新呈現,則需要在tasksCompleted更改后更改進度值。 假設tasksCompleted正確更改,您可以使用useEffect觀察變量並更新progress state。

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 中指定的 Function 將在第一次呈現時運行,並且每次數組中的值發生變化時。 由於它更新了 state,它也會觸發重新渲染。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM