【问题标题】:React function not passing down from functional to functional component反应功能没有从功能组件传递到功能组件
【发布时间】:2020-05-06 10:00:18
【问题描述】:

我非常习惯于对组件进行分类,现在正试图更习惯于钩子,所以我正在深入研究函数式组件。

遇到了一个棘手的问题,因为我无法将函数从一个功能组件向下传递给它的功能组件子组件。

在父组件中:

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)}

我错过了什么?

【问题讨论】:

  • 你说你的父组件是功能性的,但它有类组件的渲染功能
  • 我的错,我在上面更正了。它实际上是一个功能组件。
  • 您能否在不传递toggleMenu的情况下检查您是否也从代码中的其他地方渲染了NavDrawer,因为行为不应该来自您在帖子中显示的当前代码
  • toggleProductsMenu 和 toggleServicesMenu 中的event 对象是从哪里获得的?事件未定义。
  • @IkechukwuEze。就是这样。发布一个答案,我会接受的。谢谢!

标签: javascript reactjs react-hooks


【解决方案1】:

toggleProductsMenu 和 toggleServicesMenu 中的事件对象未定义。

【讨论】:

  • 奇怪的是eslint 没有抓住它。当存在此类错误时,我已将其设置为根本不编译。
  • 尝试将 eslint no-undef 规则设置为错误,检查eslint.org/docs/rules/no-undef
  • 所有规则都设置为错误,除非它们是在.eslintrc.json 中标记为off 的规则的一部分。因此,只要未定义或未使用 HMR,它就会出错并阻止它们。我唯一能想到的是,这是一个链式函数这一事实混淆了eslint
【解决方案2】:

所以在我指出两种可能的解决方案之前,请务必注意,您在父函数调用中使用了 render 方法,并且 render 方法仅用于 Class 函数,而不是 Stateless 函数。

如果你想使用无状态函数,那么你应该使用return

查看docs的区别

这里是截图:

现在进入解决方案,Stateless Functions 不应该有方法,添加它们通常被认为是不好的做法。我知道您想熟悉非类组件,但是混合使用两者并没有错,而且通常应该这样做。如果你想添加方法,你应该使用 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:我一开始关于renderreturn 的评论是针对您的代码,然后再进行编辑。我还是留在这里留给后人吧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-13
    • 2021-12-08
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 2020-05-27
    相关资源
    最近更新 更多