我正在构建一个站点,其中包含很多反应组件,但不是 SPA 或完整的反应站点。因此反应组件被拉入页面。当各种菜单的打开或下拉菜单出现时,我有一个覆盖 Ui 的覆盖组件。我遇到的问题是我已经像这样设置了我的上下文:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export const OverlayContext = React.createContext();
export class OverlayProvider extends Component {
state = {
showOverlay: true,
test: 'default test value'
}
showHideOverlay = () => {
const visible = this.state.showOverlay;
this.setState({
showOverlay: visible ? false : true
});
}
render() {
return (
<OverlayContext.Provider value={{
state: this.state,
showHideOverlay: this.showHideOverlay
}}>
{this.props.children}
</OverlayContext.Provider>
);
}
}
OverlayProvider.propTypes = {
children: PropTypes.object
}
然后我将此提供者和消费者传递给 2 个不同的组件:
- 我的覆盖组件
- 我的 MyAccount 组件。
它们在这里: 叠加层:
import React from 'react';
import { render } from 'react-dom';
import PropTypes from 'prop-types'
import { OverlayProvider, OverlayContext } from './../contexts/OverlayContext';
// Styling
import styled from 'styled-components'
import { colors } from '../global-styled-constants/colors';
import { mixins } from '../global-styled-constants/mixins';
import { sizing } from '../global-styled-constants/sizing';
//Animations
import { fadeIn } from '../global-styled-constants/animations';
import { fadeOut } from '../global-styled-constants/animations';
const PageOverlay = styled.div`
${mixins.dimensions('100%', '100%')};
${mixins.position('fixed', '0', '0')};
display: block;
background: ${colors.red};
z-index: ${sizing.zIndex2};
${props => props.showOverlay ? `animation: ${fadeIn} 1s 0.3s both;` : `animation: ${fadeOut} 1.3s both;`}
`;
// the state containing the count will be fetched via the API and delivered to this component via redux
export const Overlay = () => {
return (
<OverlayProvider>
<OverlayContext.Consumer>
{(value) => (
<PageOverlay showOverlay={value.state.showOverlay}/>
)}
</OverlayContext.Consumer>
</OverlayProvider>
);
}
render(<Overlay/>, document.getElementById('react-overlay'))
Overlay.propTypes = {
showOverlay: PropTypes.bool.isRequired
}
我的帐户:
import React, { Component, Fragment } from 'react';
import { OverlayProvider, OverlayContext } from '../../contexts/OverlayContext';
// Styling
import styled from 'styled-components'
import { colors } from '../../global-styled-constants/colors'
import { mixins } from '../../global-styled-constants/mixins'
import { sizing } from '../../global-styled-constants/sizing'
import { type } from '../../global-styled-constants/typography'
// import { mq } from '../../global-styled-constants/mediaQueries';
const Wrapper = styled.div`
position: relative;
`;
const List = styled.ul`
${mixins.dimensions('195px', 'auto')};
position: absolute;
background: ${colors.lightSmoke};
z-index: 10;
top: 38px;
padding: 15px;
${props => props.showDropdown ? `display: block;` : `display: none`};
`;
const Item = styled.li`
padding: 15px 0;
a {
font-size: ${sizing.scaleh10};
font-family: ${type.fsSanSerif};
font-weight: ${sizing.fontWeightBold};
font-style: normal;
text-decoration: none;
}
&:hover {
cursor: pointer;
color: ${colors.orange};
}
`;
const Trigger = styled.li`
${mixins.flex('center')};
height: 38px;
font-size: ${sizing.scaleh10};
padding: 0 20px;
position: relative;
color: ${colors.anotherGrey};
font-family: ${type.fsSanSerif};
font-weight: ${sizing.fontWeightBold};
font-style: normal;
text-decoration: none;
cursor: pointer;
${props => props.showDropdown && `background: ${colors.lightSmoke}; color: ${colors.orange}`};
`;
const accountData = {
"loggedOut": {
"displayCTA": "My Account",
"links": [
{
"displayName": "Sign In",
"link": "www.google.com"
},
{
"displayName": "Sign up / Join",
"link": "www.google.com"
},
{
"displayName": "Register Products",
"link": "www.google.com"
},
{
"displayName": "Subscribe to Newsletter",
"link": "www.google.com"
}
]
},
"loggedIn": {
"displayCTA": "{userEmail}",
"links": [
{
"displayName": "My Products",
"link": "www.google.com"
},
{
"displayName": "My Wishlist",
"link": "www.google.com"
},
{
"displayName": "My Orders",
"link": "www.google.com"
},
{
"displayName": "My Profile",
"link": "www.google.com"
},
{
"displayName": "Sign Out",
"link": "www.google.com"
},
{
"displayName": "Register Products",
"link": "www.google.com"
},
{
"displayName": "Newsletter Sign up",
"link": "www.google.com"
}
]
}
}
export default class MyAccount extends Component {
constructor(props) {
super(props);
this.state = {
showDropdown: false,
loggedIn: false
}
}
hoverAwakeMenu = () => {
this.setState({
showDropdown: true
})
}
mouseLeft = () => {
this.setState({
showDropdown: false
});
}
render() {
const { showDropdown, loggedIn } = this.state;
const data = loggedIn ? accountData.loggedIn.links : accountData.loggedOut.links;
const displayCTA = loggedIn ? accountData.loggedIn.displayCTA : accountData.loggedOut.displayCTA;
const itemsList = data.map((item, i) => <Item key={i}><a href={item.link}>{item.displayName}</a></Item>);
return (
<OverlayProvider>
<Fragment>
<Wrapper onMouseLeave={this.mouseLeft}>
<OverlayContext.Consumer>
{(value) => (
<Trigger showDropdown={showDropdown} onMouseEnter={(e) => {this.hoverAwakeMenu(e); value.showHideOverlay(e);}}>{displayCTA}</Trigger>
)}
</OverlayContext.Consumer>
<List showDropdown={showDropdown}>
{itemsList}
</List>
</Wrapper>
</Fragment>
</OverlayProvider>
);
}
}
当我调用 value.showHideOverlay(e); 从 MyAccount.js 它更新上下文中的状态,但它不会将此更改转发到基于此布尔值的道具“showOverlay”样式的 Overlay.js。如果我在我的帐户中放了一个测试道具,它就会得到改变。如果我从 Overlay.js 触发事件,也会发生同样的事情。覆盖层内的道具从上下文中的状态更新,但不是 MyAccount.js 中的那个
我猜我可能对多个提供者做错了什么,但我的印象是多个提供者对反应上下文 API 绝对没问题。
任何方向表示赞赏!