首页 > 解决方案 > 减速器并不总是删除正确的项目

问题描述

我的删除回调发送了正确的 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(
          // actual code
          (component: any) =>  component.id !== action.payload),
          //test code to check what ids were being passed in
          //(component: any) => { console.log(component.id, action.payload), console.log(component.id !== action.payload), component.id == action.payload }),
      };

    default:
      return state;
  }
}

Delete 案例有一行我用来测试以查看传入的 id。

上下文

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

我用来测试的 Note 组件

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 { components, 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})
  }

  const deleteNote = () => {
    deleteComponent(id)
  }

  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"
                    onClick={() => console.log(id)}
                    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={deleteNote}
                    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 newComponent = (componentType: number) => {
        addComponent({id: Math.floor(Math.random() * 100000000), componentType: componentType})
    }
    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 }) => (
                  <button
                    id="Todo"
                    onClick={() => newComponent(1)}
                    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="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"
                      />
                    </svg>
                    Todo list
                  </button>
                )}
              </Menu.Item>
              <Menu.Item>
                {({ active }) => (
                  <li
                    //onClick={() => setComponent(<Moodboard />) }
                    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="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
                      />
                    </svg>
                    Mood Board
                  </li>
                )}
              </Menu.Item>
              <Menu.Item>
                {({ active }) => (
                  <li
                    onClick={() => newComponent(2) }
                    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="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
                      />
                    </svg>
                    Image
                  </li>
                )}
              </Menu.Item>
              <Menu.Item>
                {({ active }) => (
                  <li
                    onClick={() => newComponent(3)}
                    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;

创建菜单项的组件

import React, { useContext } from "react";
import { NewComponentContext } from "../Context/NewComponentContext";
import NewComponentMenu from "./NewComponents/NewComponentMenu";
import Note from "./NewComponents/Note/Note";
import Photo from "./NewComponents/Photo/Photo";
import TodoList from "./NewComponents/Todo/TodoList";

const Board = () => {
    const { components } = useContext(NewComponentContext);

    const componentList  = components.map((component, i) => {
      if (component.componentType == 1) {
        return (
          <div key={i}>
            <TodoList id={component.id} />
          </div>
        );
      }
      else if (component.componentType == 2) {
        return (
          <div key={i}>
            <Photo id={component.id} />
          </div>
        ) 
      }
      else {
        return (
          <div key={i}>
            <Note id={component.id} />
          </div>
        )
        
      }
    });
  
    return (
      <div className="flex space-x-10 mt-8">
        <NewComponentMenu />
        <div className="grid grid-cols-6 gap-8">{componentList}</div>
      </div>
    );
  };
  
  export default Board;

标签: reactjs

解决方案


减速器中的删除案例存在问题。您没有返回布尔值,因此不会返回任何项目,

case "DELETE_COMPONENT":
      return {
        ...state,
        components: state.components.filter(
          (component: any) => { 
              console.log(component.id, action.payload)
              console.log(component.id !== action.payload)
              return component.id !== action.payload // here is the fix
            })
      };

推荐阅读