所以我想简化将props 传递给父组件的孙子组件,其中更改按钮或通道的打开或关闭状态(如:[open, setOpen]= useState())可以简化为useReducer,并从父组件传递.无论如何,我不能理解为什么我它不工作,也许我理解错了逻辑.理想情况下,我希望接近枯燥的本金,并尽可能简单地传递props . 错误: AddButtonModal.tsx:36 Warning: Failed prop type: The prop Open is marked as required in ForwardRef(模数2), but its value is 未定义.

父零部件:

import React, {useReducer, useState} from "react";
import {Ingredient} from "../../models/ingredient";
import {Box} from "@mui/material";
// Importing the 4 components for their respective part that way we have a more concise Page
import AddButtonModal from "./components/IngredientsManagementViewComponents/AddButtonModal";
import IngredientCategoryMenu from "./components/IngredientsManagementViewComponents/IngredeintCategoryMenu";
import SearchBarComponent from "./components/IngredientsManagementViewComponents/SearchBar";
import ingredientReducer, {IngredientActionTypes, initialState} from "./reducers/ingredientReducer";
import modalReducer, {ModalActionTypes, initialModalState} from "./reducers/modalReducer";
import ListOfIngredients from "./components/IngredientsManagementViewComponents/ListOfIngredients";


const IngredientsViewPage: React.FC = () => {
//states
//state of the new ingredient
  const [ingredientState, dispatch] = useReducer(ingredientReducer, initialState);
  console.log("ingredientState:", ingredientState);
// state for the open/close function for modals/buttons
  const [modalState, modalDispatch] = useReducer(modalReducer, initialModalState);
  console.log("modalState: within IVP", modalState);
  console.log("initialModalState within IVP: ", initialModalState);
  const handleOpenModal = () => { 
    console.log("Open Modal");
    modalDispatch({ type: ModalActionTypes.OPEN_MODAL}) };
  const handleCloseModal = () => { 
    console.log("Close Modal");
    modalDispatch({type: ModalActionTypes.CLOSE_MODAL}) };

  /*An object refering to the Ingredient model properties which can later be called to map each Number Input */
  const IngredientFieldsOptions = {
    carbs: {label: "Carbohydrates", value: ingredientState.carbs},
    protein: {label: "Protein", value: ingredientState.protein},
    sugar: {label: "Sugar", value: ingredientState.sugar},
    fat:{label: "Fat", value: ingredientState.fat},
    fiber: {label: "Fiber", value: ingredientState.fiber}
  }

  return (
    <Box sx={{ display: "flex", flexDirection: "column",
    bgcolor: "whitesmoke", borderRadius: "3px", borderBlockColor: "none"}}>
      {/*Search field with search lens*/}
      <Box sx={{display: "flex", flexDirection: "row", width: "100%"}}>
      <SearchBarComponent/>
      {/*Button with the + symbol, opens a modal */}
      <AddButtonModal 
      // IngredientFieldsOptions={IngredientFieldsOptions}
      isModalOpen={modalState.isModalOpen}
      handleOpenModal={handleOpenModal}
      handleCloseModal={handleCloseModal}
      />
      </Box>
      {/* Component with the Categories menu */}
      <IngredientCategoryMenu/>
      {/* Component List of Ingredients */}
      <ListOfIngredients 
        open={modalState.isModalOpen}
        handleOpenModal={handleOpenModal}
        handleCloseModal={handleCloseModal}
        ingredientState={ingredientState}
        dispatch={dispatch}
      />
    </Box>
  )
};

export default IngredientsViewPage;

子元素:

import React, {useReducer, useState} from "react";
import {Box, Button, Modal, Typography} from "@mui/material";
import Add from "@mui/icons-material/Add";
import ingredientReducer, {IngredientActionTypes, initialState} from "../../reducers/ingredientReducer.ts";
import {Ingredient} from "../../../../models/ingredient.ts";
import XButton from "./XButton.tsx";
import IngredientFields from "./IngredientFields.tsx";
import DropDowns from "./DropDown.tsx";
import CheckBoxSection from "./CheckBoxSection.tsx";
import NumberInputFields from "./NumberInputFields.tsx";
import SaveButton from "./SaveButton.tsx";
import { dummy_allergens } from "../../../../dummy_data/dummy_allergens.ts";
import { dummy_ingredients } from "../../../../dummy_data/dummy_ingredients.ts";
import { number } from "yup";


//defined types of the props 
interface AddButtonModalProps {
  isModalOpen: boolean;
  handleOpenModal: () => void;
  handleCloseModal: () => void;
} 
const AddButtonModal: React.FC<AddButtonModalProps> = ({isModalOpen, handleOpenModal, handleCloseModal}) => {
const [ingredientState, dispatch] = useReducer(ingredientReducer, initialState);
console.log("modalState: within ABM", isModalOpen);
return (
    <Box sx={{marginBottom: 2, }}>
        <Button onClick={handleOpenModal} sx={{
          minWidth: 100,
          height: "auto",
          display: "flex",
          }}
          startIcon={<Add />}
          id="Container-search bar & + button">
          Add new
          <Modal
            open={isModalOpen}
            onClose={handleCloseModal}
            aria-labelledby="modal-modal-title"
            aria-describedby="modal-modal-description"
          >
            <Box sx={{
              position: "absolute",
              top: "50%",
              left: "50%",
              transform: "translate(-50%, -50%)",
              width: "70vw",
              bgcolor: "whitesmoke",
              boxShadow: 24,
              borderRadius: "3px",
              p: 4,
              overflowY: "auto", // Scroll for overflow content
              maxHeight: "90vh",
              }} id="main container"
            onClick={(event) => event.stopPropagation()}
            >
              {/* Label & X icon button */}
              <Box sx={{display: "flex", flexDirection: "row", justifyContent: "space-between", alignItems: "center"}} 
                  id="container-title & close-icon">
              <Typography id="modal-modal-title" variant="h2" component="h2" sx={{fontSize: "1.2rem"}}>
                    ADD INGREDIENT
              </Typography>
              <XButton handleCloseModal={handleCloseModal}/>
              </Box>
              {/* Ingredients Fields Components*/}
              // name of the ingredient
              <IngredientFields />
              {/* Dropdowns components */}
              <DropDowns />
              {/* Checkboxes components */}
              <CheckBoxSection/>
              {/* Number Input */}
              <NumberInputFields 
              ingredientState={ingredientState}
              dispatch={dispatch}
              // IngredientFieldsOptions={IngredientFieldsOptions}
               />
              {/*  Save Button */}
              <SaveButton handleCloseModal={handleCloseModal}/>
            </Box>
          </Modal>
        </Button>
      </Box>
  );
};

export default AddButtonModal;

孙子:

import React from "react";
import {Box, IconButton} from "@mui/material";
import ClearIcon from '@mui/icons-material/Clear';

//defined types of the props
interface XButtonProps {
  handleCloseModal: () => void;
}
const XButton: React.FC<XButtonProps> = ({handleCloseModal}) => {
    return (
            <Box>
                  {/* Icon that closes the modal */}
                  <IconButton onClick={handleCloseModal} style={{ cursor: 'pointer' }}>
                    <ClearIcon />
                  </IconButton>
                  </Box>
    );
};

export default XButton;

后退.后退.

// Define action types related to modal operation
export enum ModalActionTypes {
OPEN_MODAL = 'OPEN_MODAL',
CLOSE_MODAL = 'CLOSE_MODAL'
}
// set opening action
type OpenModalAction = {
    type: ModalActionTypes.OPEN_MODAL
};
// set closing action
type CloseModalAction = {
    type: ModalActionTypes.CLOSE_MODAL
}
// Union type for modal-related actions
type ModalAction = OpenModalAction | CloseModalAction;
// initial state of the modal
export const initialModalState = {
    isModalOpen: false
};
/** reducer function for handling of modal state changes 
    @params {object} state: current state
    @param {ModalAction} action: action to be handled
    @returns {object} updated state of modal
    */
function modalReducer(state = initialModalState, action: ModalAction) {
    switch (action.type) {
        case ModalActionTypes.OPEN_MODAL:
            return {...state, isModalOpen: true};
        case ModalActionTypes.CLOSE_MODAL:
            return {...state, isModalOpen: false};
        default:
            return state;
        // throw Error("Unknown action: " + action.type);
    }
}

export default modalReducer;

我try 使用sole.log查看每个组件中的状态: 父零部件将显示:

modalState: within IVP , isModalOpen: false line 22,
modalState: within IVP , isModalOpen: false line 23,

点击应该打开模式的按钮后,我可以在控制台中看到

OpenModal ln 25,
modalState: within IVP , isModalOpen: true line 22,
modalState: within IVP , isModalOpen: false line 23.

我也try 了硬编码:父组件中第49行的isModalOpen={modalState.isModalOpen}.我可以分辨出,父母确实有这种状态,但不会被传递.

此外,我读了这篇文章,但我不确定这是否真的有帮助. Warning: Failed prop type: The prop open is marked as required in Snackbar, but its value is undefined

推荐答案

AddButtonModal呈现的Modal组件似乎需要openprops .AddButtonModal通过它的isModalOpenprops ,但AddButtonModal本身并不通过任何isModalOpenprops .

const IngredientsViewPage: React.FC = () => {
  ....

  return (
    <Box .... >
      <Box sx={{ .... }}>
        <SearchBarComponent />
        <AddButtonModal 
          open={true}
          handleOpenModal={handleOpenModal}
          handleCloseModal={handleCloseModal}
          // <-- no isModalOpen prop
        />
      </Box>
      ....
    </Box>
  )
};
interface AddButtonModalProps {
  isModalOpen: boolean;         // <-- 
  handleOpenModal: () => void;
  handleCloseModal: () => void;
}

const AddButtonModal: React.FC<AddButtonModalProps> = ({
  isModalOpen, // <-- undefined
  handleOpenModal,
  handleCloseModal
}) => {
  ....

  return (
    <Box sx={{marginBottom: 2 }}>
      <Button .... >
        Add new
        <Modal
          open={isModalOpen} // <-- undefined
          onClose={handleCloseModal}
          aria-labelledby="modal-modal-title"
          aria-describedby="modal-modal-description"
        >
          ....
        </Modal>
      </Button>
    </Box>
  );
};

我怀疑你的意思是通过isModalOpen,例如isModalOpen={true}isModalOpen={modalState.isModalOpen},就像对ListOfIngredients分量所做的那样.

<AddButtonModal 
  isModalOpen
  handleOpenModal={handleOpenModal}
  handleCloseModal={handleCloseModal}
/>
<AddButtonModal 
  isModalOpen={modalState.isModalOpen}
  handleOpenModal={handleOpenModal}
  handleCloseModal={handleCloseModal}
/>

我还建议将Modal组件移到按钮之外,这样模式中的任何点击都不会触发按钮的onClick处理程序并切换任何状态,例如,您可以移除onClick处理程序,该处理程序会停止Modal呈现的Box组件上的点击事件传播.

const AddButtonModal = ({
  isModalOpen,
  handleOpenModal,
  handleCloseModal
}: AddButtonModalProps) => {
  ....

  return (
    <Box sx={{marginBottom: 2 }}>
      <Button
        onClick={handleOpenModal}
        sx={{ .... }}
        startIcon={<Add />}
        id="Container-search bar & + button"
      >
        Add new
      </Button>

      <Modal // <-- outside button
        open={isModalOpen}
        onClose={handleCloseModal}
        aria-labelledby="modal-modal-title"
        aria-describedby="modal-modal-description"
      >
        <Box
          sx={{ .... }}
          id="main container"
          // <-- no onClick
        >
          ....
        </Box>
      </Modal>
    </Box>
  );
};

Reactjs相关问答推荐

Shadck/ui Select -当用户 Select 项目时更改状态

在一个地方调用函数会影响其他地方调用该函数

单击按钮时在子元素中不显示任何内容-react

For循环中的元素在Reaction中丢失挂钩

GitHub页面未正确显示Reaction应用程序网站

GitHub页面配置

如何删除 bootstrap 手风琴上的边框

定位数组中的一项(React、useState)

我无法通过 useContext 显示值

预期无限重新渲染但没有发生

为什么在 React 的 useEffect 中使用 onAuthStateChanged ?

useRef 不关注模态

Firebase查询返回随机用户数据,而不是过滤后的用户数据

React - 如何重定向页面以显示数据修改?

文本的几个词具有线性渐变 colored颜色 - React native

FlatList 不在 React Native 中呈现项目

如何在react 日历中自定义带有圆形边框的日期项?

仅在重新渲染后设置状态

如何将本地视频文件上传到 Google Cloud

Material UI 安装和 React v. 18.2 出现问题