0

在使用 React Context API 以及 useReducer 和 useContext 钩子的奇怪情况下,我有点陷入困境。

这是我的主要商店。

import React, { createContext, useReducer } from 'react';
import { Reducers } from './Reducers';
import { surveys } from '../../testData.json';

export const context = createContext();
const { Provider } = context;

export const Store = ({ children }) => {
  const [store, dispatch] = useReducer(Reducers, {
    editSurvey: { display: false },
    surveys,
  });
  return <Provider value={{ store, dispatch }}>{children}</Provider>;
};

这是我的 Reducers 函数和我的 Action 类型:

import { Actions } from './Actions';
const { DISPLAY_NEW_SURVEY, HIDE_SURVEY } = Actions;
export const Reducers = (state, action) => {
  const { type, payload } = action;
  console.log(state, action);
  switch (type) {
    case DISPLAY_NEW_SURVEY:
      return { ...state, editSurvey: { display: true } };
    case HIDE_SURVEY:
      return { ...state, editSurvey: { display: false } };
    default:
      return state;
  }
};
export const Actions = {
  DISPLAY_NEW_SURVEY: 'DISPLAY_NEW_SURVEY',
  HIDE_SURVEY: 'HIDE_SURVEY',
};

我的编辑属性中有一个显示属性,用于有条件地呈现反应门户,见下文:

import React, { useContext } from 'react';
import { EditSurveyPortal } from '../EditSurvey/EditSurveyPortal';
import { context } from '../../store/Store';

export const NavItem = ({ name, NavImage }) => {
  const { dispatch } = useContext(context);
  return (
    <div
      id={name}
      style={{ cursor: 'pointer' }}
      onClick={() => {
        dispatch({ type: 'DISPLAY_NEW_SURVEY' });
      }}
    >
      <NavImage alt={name} width={10} height={10} />
      <EditSurveyPortal />
    </div>
  );
};
import React, { useContext } from 'react';
import { createPortal } from 'react-dom';
import { context } from '../../store/Store';
import { EditSurvey } from './EditSurvey';

export const EditSurveyPortal = () => {
  const {
    store: {
      editSurvey: { display },
    },
    dispatch,
  } = useContext(context);
  return display
    ? createPortal(
        <div className="absolute top-0 left-0 w-screen h-screen z-10 flex justify-center items-center bg-gray-400 bg-opacity-50">
          <EditSurvey />
        </div>,
        document.getElementById('root'),
      )
    : null;
};

这是实际的编辑调查组件:

import React from 'react';
import { Card, CardHeader } from '../Utility/Card';
import { Close } from '../Images/Close';

export const EditSurvey = ({ dispatch }) => {
  return (
    <Card>
      <CardHeader className="flex justify-between align-center">
        <div className="inline-block relative rounded">
          <span className="absolute top-0 l-0 bg-gray-200 text-gray-800 rounded-l px-2 py-1">
            Title
          </span>
          <input type="text" className="rounded p-1" />
        </div>
        <div
          className="text-gray-800"
          style={{ cursor: 'pointer' }}
          onClick={() => {
            dispatch({ type: 'HIDE_SURVEY' });
          }}
        >
          <Close width={8} height={8} />
        </div>
      </CardHeader>
    </Card>
  );
};

我的问题是,当我单击门户上的关闭按钮时,它会分派 HIDE_SURVEY,然后立即分派 DISPLAY_NEW_SURVEY:

页面截图

我一生都无法弄清楚这一点。任何帮助将不胜感激。

谢谢!

4

1 回答 1

1

事件冒泡,伙计。

这里的问题是您EditSurvey位于 NavItem 的可点击区域下方。这里发生的是,当您单击 div 中的该 div 时EditSurvey,它首先注册对该 div 的单击,然后冒泡到您的 NavItem 可单击 div。这基本上就是所谓的event-bubbling

您可以在此处了解事件冒泡和捕获

此外,您也可以在此处检查事件冒泡问题

为了阻止事件冒泡,您可以简单地停止事件的传播。

<div
    className="text-gray-800"
    style={{ cursor: 'pointer' }}
    onClick={(event) => {
      event.stopPropagation();
      dispatch({ type: 'HIDE_SURVEY' });
    }}
  >
    <Close width={8} height={8} />
  </div>
于 2020-09-03T16:46:24.137 回答