我正在使用来自语义UI React的Modal组件;而且由于我的应用程序是根据响应性构建的,因此我发现该模式无法在不同的断点上激活-本质上,我有两个不同的组件来处理不同的断点或体验,即移动设备和台式机。因此,我决定将模态的状态添加到我的redux存储中。
但是,我发现单击按钮关闭时有行为,状态变为 false 微秒,然后又恢复为 true 。因此,外观使关闭按钮卡住或不起作用。
这是我的模态组件:
import React, { Component } from 'react'
import { Button, Modal, Transition } from 'semantic-ui-react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { logOutUser, modalStateOn, modalStateOff } from '../../store/index'
class MyModal extends Component {
close = () => {
const { modalStateOff } = this.props
modalStateOff();
}
logOutUser = () => {
const { logOutUser } = this.props
logOutUser()
}
render() {
const { modalActive } = this.props
console.log("this.props in Modal ", this.props);
return (
<>
<Modal dimmer={'blurring'} size={'mini'} open={modalActive} onClose={this.close}>
<Modal.Header>
<p>Are you sure you want to log out of your account?</p>
</Modal.Header>
<Modal.Actions>
<Button
color='black'
onClick={this.close}
>
No
</Button>
<Button
positive
icon='checkmark'
labelPosition='right'
content='Yes'
onClick={() => { this.close; this.logOutUser() }}
/>
</Modal.Actions>
</Modal>
</>
)
}
}
function mapStateToProps(state) {
const { modalActive } = state
return { modalActive }
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ logOutUser, modalStateOn, modalStateOff }, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(MyModal)
这是我的商店:
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import { persistStore } from 'redux-persist';
import { createLogger } from 'redux-logger'
import thunkMiddleware from 'redux-thunk';
/* initial state */
const startState = { isLoggedIn: false, modalActive: false }
/* action types */
export const actionTypes = {
IS_LOGGED_IN: 'IS_LOGGED_IN',
IS_LOGGED_OUT: 'IS_LOGGED_OUT',
MODAL_ACTIVE: 'MODAL_ACTIVE',
MODAL_INACTIVE: 'MODAL_INACTIVE'
}
/* reducer(s) */
export const reducer = (state = startState, action) => {
switch (action.type) {
case actionTypes.IS_LOGGED_IN:
return Object.assign({}, state, {
isLoggedIn: true,
});
case actionTypes.IS_LOGGED_OUT:
return Object.assign({}, state, {
isLoggedIn: false,
});
case actionTypes.MODAL_ACTIVE:
return Object.assign({}, state, {
modalActive: true
});
case actionTypes.MODAL_INACTIVE:
return Object.assign({}, state, {
modalActive: false
});
default:
return state
}
};
/* actions */
export const logInUser = () => {
return { type: actionTypes.IS_LOGGED_IN }
}
export const logOutUser = () => {
return { type: actionTypes.IS_LOGGED_OUT }
}
export const modalStateOn = () => {
return { type: actionTypes.MODAL_ACTIVE, modalActive: true}
}
export const modalStateOff = () => {
return { type: actionTypes.MODAL_INACTIVE, modalActive: false }
}
export default () => {
let store;
const isClient = typeof window !== 'undefined';
if (isClient) {
const { persistReducer } = require('redux-persist');
const storage = require('redux-persist/lib/storage').default;
const persistConfig = {
key: 'primary',
storage,
whitelist: ['isLoggedIn', 'modalActive'], // place to select which state you want to persist
}
store = createStore(
persistReducer(persistConfig, reducer),
startState,
composeWithDevTools(applyMiddleware(
thunkMiddleware,
createLogger({ collapsed: false })
))
);
store.__PERSISTOR = persistStore(store);
} else {
store = createStore(
reducer,
startState,
composeWithDevTools(applyMiddleware(
thunkMiddleware,
createLogger({ collapsed: false })
))
);
}
return store;
};
谢谢!
更新
根据下面的kkesley,决定在我的console.log
动作函数中modalStateOn
:
export const modalStateOn = () => {
console.log('In modalStateOn action')
return { type: actionTypes.MODAL_ACTIVE, modalActive: true}
}
这是我回来的屏幕截图:
这是调用Modal
的组件:
import React, { Component } from 'react'
import { Link, NavLink, withRouter } from 'react-router-dom'
import Modal from '../components/Modal/MyModal.jsx'
import {
Container,
Menu,
Responsive,
Segment,
Visibility,
Sidebar,
Icon,
Button
} from 'semantic-ui-react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { modalStateOn, modalStateOff } from '../store/index'
const getWidth = () => {
const isSSR = typeof window === 'undefined'
return isSSR ? Responsive.onlyTablet.minWidth : window.innerWidth
}
const logOutMenuItemHelper = (isMobile, isLoggedIn, history, modalActive, nav, NavLink, modalStateOn, modalStateOff, handleSidebarHide) => {
function mobilelogOutMenuItemHelper(history, modalActive, nav, NavLink, modalStateOn, modalStateOff, handleSidebarHide) {
if (nav.name === 'Log in') {
console.log("mobile nav.name ", nav.name);
return (
<Menu.Item
key="/logout"
name='Log out'
onClick={(event) => { modalStateOn(); handleSidebarHide();}}>
{modalActive ? <Modal history={history} isLoggedIn={isLoggedIn} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} /> : 'Log Out'}
</Menu.Item>
)
} else {
return (
<Menu.Item
exact
key={nav.name}
as={NavLink}
to={nav.path}
name={nav.name}
onClick={() => {
handleSidebarHide()
}}
>
</Menu.Item>
)
}
}
function desktoplogOutMenuItemHelper(history, modalActive, nav, NavLink, modalStateOn, modalStateOff) {
if (nav.name === 'Log in') {
// console.log("desktop nav.name ", nav.name);
return (
<Menu.Item
key="/logout"
name='Log out'
onClick={() => { modalStateOn(); }}>
{(modalActive) ? <Modal history={history} isLoggedIn={isLoggedIn} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} /> : 'Log Out'}
</Menu.Item>
)
} else {
return (
<Menu.Item
exact
key={nav.name}
as={NavLink}
to={nav.path}
name={nav.name}
>
</Menu.Item>
)
}
}
if (isMobile && isLoggedIn) {
return mobilelogOutMenuItemHelper(history, modalActive, nav, NavLink, modalStateOn, modalStateOff, handleSidebarHide)
}
return desktoplogOutMenuItemHelper(history, modalActive, nav, NavLink, modalStateOn, modalStateOff)
}
class DesktopContainer extends Component {
state = {}
hideFixedMenu = () => this.setState({ fixed: false })
showFixedMenu = () => this.setState({ fixed: true })
render() {
const { fixed } = this.state;
const { history, data, children, isLoggedIn, modalActive, modalStateOn, modalStateOff } = this.props
console.log("this.props desktop in LinkNAV ", this.props);
return (
<Responsive getWidth={getWidth} minWidth={Responsive.onlyTablet.minWidth}>
<Visibility
once={false}
onBottomPassed={this.showFixedMenu}
onBottomPassedReverse={this.hideFixedMenu}
>
<Segment
inverted
textAlign='center'
style={{ minHeight: 'auto', padding: '0' }}
vertical
>
<Menu
fixed={fixed ? 'top' : null}
inverted={!fixed}
pointing={!fixed}
secondary={!fixed}
size='large'
>
{/* {console.log("isLoggedIn in desktop homecomponent ", isLoggedIn)} */}
{isLoggedIn ?
data.filter(function (nav) {
return (nav.name !== "Register")
})
.map(nav => {
return (
logOutMenuItemHelper(false, isLoggedIn, history, modalActive, nav, NavLink, modalStateOn, modalStateOff)
)
})
:
data.filter(function (nav) {
return (nav.name != "Profile") && (nav.name != "Dashboard")
})
.map(nav => {
return (
<Menu.Item
exact
key={nav.path}
as={NavLink}
to={nav.path}
name={nav.name}
>
</Menu.Item>
)
})}
</Menu>
</Segment>
</Visibility>
{children}
</Responsive>
);
}
}
class MobileContainer extends Component {
state = {}
handleSidebarHide = () => this.setState({ sidebarOpened: false })
handleToggle = () => this.setState({ sidebarOpened: true })
render() {
const { children, history, data, isLoggedIn, modalActive, modalStateOn, modalStateOff } = this.props
const { sidebarOpened} = this.state
console.log("this.props inMobile ", this.props);
return (
<Responsive
as={Sidebar.Pushable}
getWidth={getWidth}
maxWidth={Responsive.onlyMobile.maxWidth}
>
<Sidebar
as={Menu}
animation='push'
inverted
onHide={this.handleSidebarHide}
vertical
visible={sidebarOpened}
>
{/* {console.log("isLoggedIn in desktop homecomponent ", isLoggedIn)} */}
{isLoggedIn ?
data.filter(function (nav) {
return (nav.name !== "Register")
})
.map(nav => {
return (
logOutMenuItemHelper(false, isLoggedIn, history, modalActive, nav, NavLink, modalStateOn, modalStateOff, this.handleSidebarHide)
)
})
:
data.filter(function (nav) {
return (nav.name != "Profile") && (nav.name != "Dashboard")
})
.map(nav => {
return (
<Menu.Item
exact
key={nav.name}
as={NavLink}
to={nav.path}
name={nav.name}
onClick={this.handleSidebarHide}
>
</Menu.Item>
)
})}
</Sidebar>
<Sidebar.Pusher dimmed={sidebarOpened}>
<Segment
inverted
textAlign='center'
style={{ minHeight: 'auto', padding: '1em 0em' }}
vertical
>
<Container>
<Menu inverted pointing secondary size='large'>
<Menu.Item onClick={this.handleToggle}>
<Icon name='sidebar' />
</Menu.Item>
<Menu.Item position='right'>
<Button inverted>
{isLoggedIn
? <Link to="/">Log out</Link>
: <Link to="/login">Log in</Link>
}
</Button>
{!isLoggedIn ? <Button inverted style={{ marginLeft: '0.5em' }}>
<Link to="/register"><span>Register!</span></Link>
</Button>: null}
</Menu.Item>
</Menu>
</Container>
</Segment>
{children}
</Sidebar.Pusher>
</Responsive>
);
}
}
const LinkNavWithLayout = ({ GenericHeadingComponent, children, history, data, modalActive, modalStateOn, modalStateOff, isLoggedIn }) => (
<React.Fragment>
<DesktopContainer GenericHeadingComponent={GenericHeadingComponent} history={history} data={data} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} isLoggedIn={isLoggedIn}>
{children}
</DesktopContainer>
<MobileContainer GenericHeadingComponent={GenericHeadingComponent} history={history} data={data} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} isLoggedIn={isLoggedIn}>
{children}
</MobileContainer>
</React.Fragment>
)
function mapStateToProps(state) {
const { isLoggedIn, modalActive } = state
return { isLoggedIn, modalActive }
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ modalStateOn, modalStateOff }, dispatch)
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LinkNavWithLayout))
添加throw new Error('test')
到...
export const modalStateOn = () => {
throw new Error('test')
return { type: actionTypes.MODAL_ACTIVE, modalActive: true}
}
它产生了,
答案 0 :(得分:1)
我认为您需要停止传播click事件,以便不调度modalStateOn()动作。
return (
<Menu.Item
key="/logout"
name='Log out'
onClick={(event) => { event.stopPropagation(); modalStateOn(); handleSidebarHide();}}>
{modalActive ? <Modal history={history} isLoggedIn={isLoggedIn} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} /> : 'Log Out'}
</Menu.Item>
)
答案 1 :(得分:1)
我认为您可以退货
<>
{modalActive && <Modal history={history} isLoggedIn={isLoggedIn} modalActive={modalActive} modalStateOn={modalStateOn} modalStateOff={modalStateOff} />}
<Menu.Item
key="/logout"
name='Log out'
onClick={(event) => { modalStateOn(); handleSidebarHide();}}>
Log Out
</Menu.Item>
</>
请注意,您必须为每个呈现模态的
<Menu.Item/>
执行此操作
该错误是因为当您单击模式时,事件也会传播到菜单项。