使用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',
};
我的edit属性中有一个display属性,用于有条件地渲染反应门户,请参见下文:
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:
我一生无法解决这个问题。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:1)
事件冒泡,伙伴。
这里的问题是您的EditSurvey
在NavItem的可点击区域下方。
这里发生的是,当您在EditSurvey
中单击该div时,它将首先注册对该div的单击,然后冒泡直至您的NavItem可点击的div。这基本上就是所谓的event-bubbling
您可以了解事件冒泡和捕获here
此外,您还可以检查事件冒泡问题here
为了阻止事件冒泡,您只需停止事件的传播即可。
<div
className="text-gray-800"
style={{ cursor: 'pointer' }}
onClick={(event) => {
event.stopPropagation();
dispatch({ type: 'HIDE_SURVEY' });
}}
>
<Close width={8} height={8} />
</div>