#javascript #reactjs #react-redux
Вопрос:
У меня возникла проблема с добавлением нового элемента в переменную массива состояний. В компоненте «Раздел категорий» я вызываю .push (), чтобы добавить «new_category» в массив «категории», но ничего не происходит, даже ошибки.
Когда я пытаюсь создать новую категорию, вызвав «handleAddCategory», которая запускает отправку для «createCategory», я вижу в Redux DevTools, что она была добавлена в состояние «элемент», как только я получу данные из своего бэкенда, но затем, когда .push() вызывается в компоненте «Раздел категорий», как я уже говорил, ничего не происходит.
Это действительно странно, потому что я выполняю тот же процесс в другой части своего проекта, и там он работает просто отлично. Например, я создаю новую задачу, и при получении этой созданной задачи обратно из моего бэкенда я помещаю ее в переменную состояния элементов, а затем компонент повторно визуализируется.
Редуктор категории
const initialState = {
items: [],
item: {},
}
const reducer = (state=initialState, action) => {
switch(action.type) {
case GET_CATEGORIES:
return {
...state,
items: action.payload
}
case CREATE_CATEGORY:
return {
...state,
item: action.payload
}
default:
return state;
}
};
export default reducer;
Действия категории
export const getCategories = () => {
return async(dispatch) => {
const res = await fetch('/api/get-categories/', {
method: 'GET',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-Type': 'application/json'
}
});
const data = await res.json();
dispatch({
type: GET_CATEGORIES,
payload: data
});
}
}
export const createCategory = (name) => {
return async(dispatch) => {
const res = await fetch('/api/manage-category/', {
method: 'POST',
headers: {
'X-CSRFToken': getCookie('csrftoken'),
'Content-type': 'application/json'
},
body: JSON.stringify({'name': name})
});
const data = await res.json();
dispatch({
type: CREATE_CATEGORY,
payload: data
});
}
}
Компонент категоризации
Здесь я пытаюсь вызвать .push во втором эффекте использования, потому что sumTasks() должен вызываться только при изменении «категорий», но, к сожалению, он вообще не нажимает…
import React from 'react'
import CategoryItem from './CategoryItem'
import AddPopover from '../popovers/AddPopover'
import { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { getTasks } from '../../state/action-creators/taskActions';
import { createCategory, setActiveCategory } from '../../state/action-creators/categoryActions';
const CategorySection = () => {
const dispatch = useDispatch();
const categories = useSelector((state) => state.category.items);
const new_category = useSelector((state) => state.category.item);
const active_category = useSelector((state) => state.category.active);
const [anchorEl, setAnchorEl] = useState(null);
const [totalTasks, setTotalTasks] = useState(0);
const open = Boolean(anchorEl);
useEffect(() => {
sumTasks();
}, [categories])
useEffect(() => {
categories.push(new_category);
}, [new_category])
function sumTasks() {
let sum = categories.reduce((total, current) => total = total current.total_tasks, 0);
setTotalTasks(sum);
}
const onCategoryClick = async (id) => {
if(active_category != id) {
await dispatch(setActiveCategory(id));
await dispatch(getTasks());
}
}
const single_category = categories amp;amp; categories.map((category) => {
return(
<CategoryItem key={category.id} category={category} active_category={active_category} onCategoryClick={onCategoryClick} />
)
})
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleAddCategory = async (e, value) => {
if(e.keyCode === 13 amp;amp; value != '') {
setAnchorEl(null);
await dispatch(createCategory(value));
}
}
return (
<div className="bg-dark mb-3" id="category-wrapper">
<div className="container mt-2 mb-2">
<div className="row">
<span className="d-flex justify-content-between">
<div className="fs-4 text-white">
Categories
</div>
<div className="category-tooltip-div" data-bs-toggle="tooltip" data-bs-placement="right" title="">
<svg onClick={handleClick} xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="orange" id="sidebar-add-category"
className="bi bi-plus-square rename-add-icon category-add-icon global-add-category-icon" viewBox="0 0 16 16">
<path
d="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z" />
<path
d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
<AddPopover
open={open}
anchorEl={anchorEl}
horizontal={30}
onClose={handleClose}
placeholder="Enter Category name"
handlePressEnter={handleAddCategory}
/>
</div>
</span>
</div>
</div>
<div className="container" id="sidebar-categories">
<li className={`row hovered-nav-item active-category ${active_category == -1 ? "item-selected" : ""}`}>
<span onClick={() => onCategoryClick(-1)} className="category-link category-item fs-5 d-flex " id="sidebar-all-tasks" value="-1">
<div className="all-tasks-text">All</div>
{totalTasks > 0 ? (
<div className="total-number">
<div className="number">{totalTasks}</div>
</div>
):''}
</span>
</li>
<div id="categories-loop">
{single_category}
</div>
</div>
</div>
)
}
export default CategorySection
Комментарии:
1. Вы не должны изменять категории с помощью push, но создайте действие, которое добавляет неизменяемый элемент в массив
2. Я изучил возможность добавления в массив состояний и опубликовал ответ ниже. Дело в том, что я просматривал учебник Трэвиса по медиа-редактированию на YT, и он использовал .push (), чтобы добавить новую запись в массив, и это работало…
3. Возможно, он использовал immer в этом контексте с набором инструментов redux, может быть? Но все еще в действии, вероятно?
Ответ №1:
Я изменил редуктор CREATE_CATEGORY на:
case CREATE_CATEGORY:
return {
...state,
items: [...state.items, action.payload]
}