我已经非常习惯于对组件进行分类,现在尝试让更多的人习惯使用钩子,所以我将深入研究功能组件。
遇到一个棘手的问题,因为我无法将一个函数从一个功能组件传递给其功能组件子组件。
在父组件中:
import React, { useState, useEffect } from 'react';
import { Link } from 'gatsby';
import { MenuList, MenuItem } from '@material-ui/core';
import { withCookies, Cookies } from 'react-cookie';
import { ExpandMore } from '@material-ui/icons';
import PropTypes from 'prop-types';
import styles from '../styles/nav.module.scss';
import NavDrawer from './navDrawer';
const activeStyle = {
color: '#445565',
backgroundColor: '#de1b',
borderColor: '#ced4da',
};
const NavMobile = (props) => {
const [isOpenProductsMenu, setIsOpenProductsMenu] = useState(false);
const [isOpenServicesMenu, setIsOpenServicesMenu] = useState(false);
const [isAdmin, setIsAdmin] = useState(false);
const { cookies, categories } = props;
const main = process.env.ROOT_CATEGORIES.split(',');
useEffect(() => {
if (cookies.get('roles')) {
const roles = cookies.get('roles');
setIsAdmin(!!roles.includes('ROLE_ADMIN') || roles.includes('ROLE_SUPERADMIN'));
}
});
const toggleProductsMenu = (isOpen) => {
if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) {
return;
}
setIsOpenProductsMenu(isOpen);
};
const toggleServicesMenu = (isOpen) => {
if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) {
return;
}
setIsOpenServicesMenu(isOpen);
};
return (
<MenuList className={styles.navMobile} style={{ padding: '0 10px 0 0' }}>
<MenuItem disableGutters>
<Link to="/" activeStyle={activeStyle}>Home</Link>
</MenuItem>
<MenuItem disableGutters>
<Link to="/search" activeStyle={activeStyle}>Search</Link>
</MenuItem>
<MenuItem
onMouseEnter={() => toggleProductsMenu(true)}
onMouseLeave={() => toggleProductsMenu(false)}
className={styles.overrideItem}
disableGutters
>
<NavDrawer
type={main[0]}
open={isOpenProductsMenu}
categories={categories}
toggleMenu={toggleProductsMenu}
/>
<Link to="/" onClick={(event) => event.preventDefault}>
<div className={styles.itemWrap}>
{main[0]}
<ExpandMore />
</div>
</Link>
</MenuItem>
<MenuItem
onMouseEnter={() => toggleServicesMenu(true)}
onMouseLeave={() => toggleServicesMenu(false)}
className={styles.overrideItem}
disableGutters
>
<NavDrawer
type={main[1]}
open={isOpenServicesMenu}
categories={categories}
toggleMenu={toggleServicesMenu}
/>
<Link to="/" onClick={(event) => event.preventDefault}>
<div className={styles.itemWrap}>
{main[1]}
<ExpandMore />
</div>
</Link>
</MenuItem>
{isAdmin ?
(
<MenuItem disableGutters>
<Link to="/admin" activeStyle={activeStyle}>Admin</Link>
</MenuItem>
) : null}
</MenuList>
);
};
NavMobile.propTypes = {
cookies: PropTypes.instanceOf(Cookies).isRequired,
categories: PropTypes.array.isRequired,
};
export default withCookies(NavMobile);
但是,如果我尝试按以下方式访问子组件中的道具,则toggleMenu
函数将不会出现在输出中;
当然会抛出一个type error
。
export default function NavDrawer(props) {
const {
type,
open,
categories,
toggleMenu,
} = props;
console.log('props drawer', props);
<Drawer
id={`parentDrawer-${type}`}
onMouseEnter={() => setIsOpenSubDrawer(true)}
onMouseLeave={() => setIsOpenSubDrawer(false)}
className={classes.drawer}
variant="temporary"
open={open}
close={toggleMenu(false)}
我想念什么?
答案 0 :(得分:1)
因此,在我指出两种可能的解决方案之前,请务必注意,您在父函数调用中使用了render
方法,并且render
方法仅在Class函数中使用,而没有Stateless功能。
如果要使用无状态功能,则应使用return
。
查看docs
中的区别这是屏幕截图:
现在进入解决方案,Stateless Functions
不应该拥有方法,将它们添加通常被认为是不好的做法。我知道您想熟悉非Class组件,但同时使用这两种组件并没有错,通常这就是应该这样做的方式。如果要添加方法,则应使用Class Component
并按 this :
class NavMobile extends Component {
constructor(props) {
super(props);
this.state = {
// Empty for now
}
}
toggleMenu = () => {
// Your code
}
render() {
return (
// More code
<Navbar toggleMenu={this.toggleMenu} />
// More code
)
}
}
之所以认为这是不好的做法,是因为每次调用组件时都会重新定义函数toggleMenu()
。
如果您真的想继续进行此操作,则应在组件函数之外声明该函数,以便仅声明一次函数并使用相同的引用。
您应该尝试以下方法:
const toggleMenu = (isOpen) => { ... };
并在这样的组件中调用它
const NavMobile = (props) => {
return (
// Your code
<NavBar toggleMenu={toggleMenu.bind(null, propsYouWantToPass} />
)
}
最后,似乎您正在函数内部寻找事件对象,例如(event.type === 'keydown')
,但不会传递此类事件,因为在子组件NavBar
中,您使用了false
参数来调用它。
让我知道是否有帮助。
PS:在开始进行编辑之前,我最初对render
与return
的评论是针对您的代码的。我仍将其留在这里供后代使用。