reactjs 按钮组件无法与useContext挂钩一起使用

dhxwm5r4  于 2023-02-15  发布在  React
关注(0)|答案(2)|浏览(174)

我正在练习useContext挂钩与Next.js,如果它的问题,并创建了一个小网站,改变背景颜色的<Paragraph></Paragraph>元素打印文本和<Button></Button>元素改变主题。我组织它与<Layout />的按钮和段落的地方。
正如在教程中所写的,我可以将这个主题更改逻辑放入onClick方法中,它将工作。它实际上工作,但前提是我放入一个简单的<button></button>元素,而不是react组件:

<ThemeContext.Provider value={theme}>
                  <Paragraph>Hello Context</Paragraph>
 // Doesn't work ---> <Button type="button" onClick={() => {theme === 'dark' ? setTheme('light') : setTheme('dark')}}>Change theme</Button>
 // Works        ---> <button type="button" onClick={() => {theme === 'dark' ? setTheme('light') : setTheme('dark')}}>Change theme</button>
            </ThemeContext.Provider>

Paragraph.tsx:

import { useContext, useState, ReactNode, DetailedHTMLProps, HTMLAttributes } from 'react';
import styles from './Paragraph.module.scss'
import cn from 'classnames'
import { ThemeContext } from '../../Layout/Layout'

interface ParagraphProps extends DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement> {  
      children: ReactNode
}

export const Paragraph = ({ children, className }: ParagraphProps): JSX.Element => {
      const theme = useContext<string>(ThemeContext)

      return (
            <p className={cn(styles.p, className, {
                  [styles.paraDark]: theme === 'dark',
                  [styles.paraLight]: theme === 'light'
            })}>
                  {children}
            </p>
      )
}

Button.tsx:

import { DetailedHTMLProps, ButtonHTMLAttributes, ReactNode, useContext, useState, MouseEventHandler } from 'react';
import { ThemeContext } from 'Layout/Layout';
import cn from 'classnames'
import styles from './Button.module.scss'

interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
      children: ReactNode
}
 
export const Button = ({ children, className}: ButtonProps ): JSX.Element => {
      const theme = useContext<string>(ThemeContext)

      return (
            <button
                  className={cn(styles.button, className, {
                        [styles.buttonDark]: theme === 'dark',
                        [styles.buttonLight]: theme === 'light'
                  })}
            >
                  {children}
            </button>
      )
}

Layout.tsx:

import { Paragraph, Button } from "Components";
import { createContext, useState } from 'react';

interface Layout {}

export const ThemeContext = createContext<string>('')

export const Layout = (): JSX.Element => {
      const [theme, setTheme] = useState<string>('dark')

      // Putting this function into onClick event also doesn't help
      const handleChangeThemeButtonClick = () => {
            if (theme === 'dark')
                  setTheme('light')
            else if (theme === 'light')
                  setTheme('dark')
      }

      return (
            <ThemeContext.Provider value={theme}>
                  <Paragraph>Hello Context</Paragraph>
                  <Button type="button" onClick={() => {theme === 'dark' ? setTheme('light') : setTheme('dark')}}>Change theme</Button>
                  <button type="button" onClick={() => {theme === 'dark' ? setTheme('light') : setTheme('dark')}}>Change theme</button>
            </ThemeContext.Provider>
      )
}

我是在react beta docs上学习这个钩子的,我的代码看起来和本教程中写的一样。

7kqas0il

7kqas0il1#

您的Button组件没有onClick属性。
您需要将其作为prop传递下来,并从原生按钮onClick属性调用它。
由于您使用的是typescript,因此请为其给予适当的类型MouseEventHandler<HTMLButtonElement>,并将其标记为可选(在类型声明中的属性名称后加上?),以防您希望在不使用onClick事件的情况下使用Button。

import { DetailedHTMLProps, ButtonHTMLAttributes, ReactNode, useContext, useState, MouseEventHandler } from 'react';
import { ThemeContext } from 'Layout/Layout';
import cn from 'classnames'
import styles from './Button.module.scss'

interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
      children: ReactNode
      onClick?: MouseEventHandler<HTMLButtonElement> // <= pass it down as a prop with the appropriate type
}
 
export const Button = ({ children, className, onClick }: ButtonProps ): JSX.Element => {
      const theme = useContext<string>(ThemeContext)

      return (
            <button
                  className={cn(styles.button, className, {
                        [styles.buttonDark]: theme === 'dark',
                        [styles.buttonLight]: theme === 'light'
                  })}
                  onClick={onClick}
            >
                  {children}
            </button>
      )
}
p8h8hvxi

p8h8hvxi2#

您似乎尚未向Button组件添加onClick处理程序。您可以向Button组件内的button元素添加onClick事件侦听器,如下所示:

import { DetailedHTMLProps, ButtonHTMLAttributes, ReactNode } from 'react';

interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  children: ReactNode;
  className?: string;
  onClick?: () => void;
}

export const Button = ({ children, className, onClick }: ButtonProps): JSX.Element => {
  return (
    <button className={className} onClick={onClick}>
      {children}
    </button>
  );
};

不要忘记处理onClick的 prop ,我建议称之为其他东西,如“onPress”,不要与本机onClick事件混淆。

相关问题