useReducer钩子和reducer函数的问题



我认为这主要是我的减速器功能的问题,但基本上我试图添加和删除组件。添加效果很好。删除不能正常工作。当我创建一个新组件时,我在onClick中放了一个控制台日志,它显示了唯一的id,但它似乎没有正确地传递到减速器或其他东西。如果谁有什么主意,我洗耳恭听。

减速机功能

export default function reducer(state: any, action: any) {
switch (action.type) {
case "ADD_COMPONENT":
return {
...state,
components: [...state.components, action.payload],
};
case "DELETE_COMPONENT":
return {
...state,
components: state.components.filter(
(component: any) => component.id == action.payload
),
};
default:
return state;
}
}

对于Delete,它是过滤和检查id,用这种方式(组件)。Id == action.payload),则删除所有组件。如果我有!===行动。有效载荷,它不删除任何东西

上下文

import React, { createContext, useReducer, useState } from "react";
import ComponentReducer from "./ComponentReducer";
const NewComponentState: NewComponentsState = {
components: [],
addComponent: () => {},
deleteComponent: () => {},
};
export const NewComponentContext =
React.createContext<NewComponentsState>(NewComponentState);
export const NewComponentProvider: React.FC = ({ children }) => {

const [state, dispatch] = useReducer(ComponentReducer, NewComponentState);
const addComponent = (component: any) => {
dispatch({
type: "ADD_COMPONENT",
payload: component
});
};
const deleteComponent = (id: any) => {
dispatch({
type: "DELETE_COMPONENT",
payload: id,
});
};
return (
<NewComponentContext.Provider
value={{ components: state.components, deleteComponent, addComponent }}
>
{children}
</NewComponentContext.Provider>
);
};

Notes组件。这是我用

测试的组件
import { Menu,Transition } from "@headlessui/react";
import React, { useState, Fragment, useContext } from "react";
import NoteColorChanger from "./NoteColor";
import Draggable from 'react-draggable';
import { NewComponentContext } from "../../../Context/NewComponentContext";
interface INote {
id: any
}
const Note: React.FC <INote> = ({ id }) => {
const [content, setContent] = useState<string>()
const [title, setTitle] = useState<string>()
const [color, setColor] = useState<any>()
const [position, setPosition] = useState<any>({x: 0, y: 0})
const {deleteComponent} = useContext(NewComponentContext)
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setContent(event.target.value)
};
const handleColor = (notecolor: any) => {
setColor(notecolor)
}
const trackPosition = (pos:any) => {
setPosition({x: pos.x, y: pos.y})
}
return ( 
<div className={`${color} h-64 w-64 bg-yellow-200 text-black rounded-lg p-2 shadow-lg`}>
<div className="flex justify-between items-center pb-6">
<h1 className="font-bold font-Inter">Note</h1>
<Menu>
<Menu.Button>
<div className={`hover:${color} p-1 rounded-lg ease-in-out duration-100`}>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1}
d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z"
/>
</svg>
</div>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items
as="div"
className={`bg-gray-100 font-Inter w-64 shadow-lg rounded-lg absolute translate-y-24 -translate-x-2 z-50`}
>
<Menu.Item>
{({ active }) => (
<div
id="color"
className={` flex items-center py-2 px-3 rounded-lg w-full`}
>
{<NoteColorChanger handleColor={handleColor}/>}


</div>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<button
id="Todo"
className={`${
active ? "bg-blue-500 text-white" : "text-black"
} flex items-center py-2 px-3 rounded-lg w-full`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 mr-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
Edit Title
</button>
)}
</Menu.Item>
<Menu.Item>
{({ active }) => (
<li
onClick={() => deleteComponent(id)}
className={`${
active ? "bg-blue-500 text-white" : " text-black"
} flex items-center py-2 px-3 cursor-pointer rounded-lg`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 mr-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
/>
</svg>
Delete Note
</li>
)}
</Menu.Item>

</Menu.Items>
</Transition>
</Menu>
</div>
<textarea
className={`${color} bg-yellow-200 font-Inter w-full h-48 border-none focus:border-none focus:ring-0 resize-none`}
onChange={() => {handleChange}}
/>
</div>

);
};
export default Note;

菜单组件
import React, { useContext, Fragment, useState } from "react"
import { NewComponentContext } from "../../Context/NewComponentContext"
import { Menu, Transition } from '@headlessui/react'
import Note from "./Note/Note";
import TodoList from "./Todo/TodoList";
import Photo from "./Photo/Photo";
const NewComponentMenu = () => {
const { addComponent } = useContext(NewComponentContext)
const [id, setId] = useState<number>(0)
const newComponent = (component: any) => {
setId(Math.floor(Math.random() * 100000000))
addComponent(component)
}
return (
<div className="w-6 h-6 mt-4 ml-4 shadow-md text-gray-800 font-Inter z-50">
<Menu>
<Menu.Button>
<div className="p-1 rounded-lg bg-blue-500 hover:bg-blue-600 ease-in-out duration-100">
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 text-blue-50"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fillRule="evenodd"
d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z"
clipRule="evenodd"
/>
</svg>
</div>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items as="div" className="w-60 shadow-lg rounded-lg bg-white">
<h1 className="text-center font-Inter text-2xl pb-2">Items</h1>

<Menu.Item>
{({ active }) => (
<li
onClick={() => newComponent(<Note id={id}/>) }
className={`${
active ? "bg-blue-500 text-white" : " text-black"
} flex items-center py-2 px-3 cursor-pointer rounded-lg`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6 mr-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
Note
</li>
)}
</Menu.Item>
</Menu.Items>
</Transition>
</Menu>
</div>
);
};

export default NewComponentMenu;

Issue

问题是你没有传递具有id属性的对象到addComponent回调。您正在传递一个JSX字面量。将JSX存储到任何React状态通常是一种反模式,你应该存储数据并在渲染时将其映射到JSX。

<标题>

解决方案传递具有id属性的对象。在更新状态时,您只需要一个函数来生成一个id,因此NewComponentMenu中的id状态是不必要的。

const NewComponentMenu = () => {
const { addComponent } = useContext(NewComponentContext);
const newComponent = () => {
addComponent({
id: Math.floor(Math.random() * 100000000),
});
};
return (
...
<Menu.Item>
{({ active }) => (
<li
onClick={newComponent}
className={`${
active ? "bg-blue-500 text-white" : " text-black"
} flex items-center py-2 px-3 cursor-pointer rounded-lg`}
>
...
</li>
)}
</Menu.Item>
...
);
};

现在您正在存储具有id属性的数据元素对象,那么delete情况应该可以工作了。

当渲染state.components时,您需要映射到Note组件。

const { components } = useContext(NewComponentContext);
...
{components.map(el => <Note id={el.id}/>)}

最新更新