【问题标题】:unable to use hooks in a component that is being returned无法在返回的组件中使用挂钩
【发布时间】:2021-09-12 01:00:43
【问题描述】:

我正在关注 React.js 教程。

在其中,使用基于类的组件创建了一个网站。但是现在,它正在被转换为功能组件。

这是一个 HOC,最初返回一个基于类的组件,但现在是一个函数式组件。

现在,当我在其中使用 useState 和 useEffect 时,会出现以下错误:

Line 8:36:  React Hook "useState" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function

Line 29:9:  React Hook "useEffect" cannot be called inside a callback. React Hooks must be 
called in a React function component or a custom React Hook function

我使用的是 react 版本 17,而讲师使用的是版本 16。

这是基于类且工作时的代码:


import React, {Component} from 'react'
import Modal from "../../components/UI/Modal/Modal";
const WithErrorHandler = (WrappedComponent , axios) =>
{
    return class extends Component
    {
        state = {
            error : null
        }
        componentWillMount()
        {

            this.resInterceptor = axios.interceptors.response.use(res => res , (error) =>
            {
                this.setState({error : error});

            });

            
            this.reqInterceptor =axios.interceptors.request.use((req) =>
            {

                this.setState({error : null});
                
                return(req);
            } );


        }
       
        componentWillUnmount()
        {
            axios.interceptors.request.eject(this.reqInterceptor);
            axios.interceptors.response.eject(this.resInterceptor);

        }

        errorConfirmedHandler = () =>
        {
            this.setState({error : null});
        }

        render()
        {
            return(
                <>
                <Modal 
                show = {this.state.error}
                modalClosed = {this.errorConfirmedHandler}>
                    {this.state.error ? this.state.error.message : null}
                </Modal>
                <WrappedComponent {...this.props}/>
                </>
            );
        }
    }
    
}

export default  WithErrorHandler;

这是转换为功能组件并且不工作时的代码:


import React, {useState , useEffect} from 'react'
import Modal from "../../components/UI/Modal/Modal";
const WithErrorHandler = (WrappedComponent , axios) =>
{

    return props => {
        const [error , seterror] = useState(null);
        
        
            const resInterceptor = axios.interceptors.response.use(res => res , (error) =>
            {
                seterror(error);

            });

            
            const reqInterceptor =axios.interceptors.request.use((req) =>
            {

                seterror(null);
                
                return(req);
            } );


        

        useEffect(() =>
        {
            return () =>
            {
                axios.interceptors.request.eject(reqInterceptor);
                axios.interceptors.response.eject(resInterceptor);
            }

        } , [reqInterceptor , resInterceptor])
        

        const errorConfirmedHandler = () =>
        {
            seterror(null);
        }

        
            return(
                <>
                <Modal 
                show = {error}
                modalClosed = {errorConfirmedHandler}>
                    {error ? error.message : null}
                </Modal>
                <WrappedComponent {...props}/>
                </>
            );
        
    }
    
}

export default  WithErrorHandler;

任何帮助或指导将不胜感激,谢谢。

【问题讨论】:

  • 能否包含实例化 HOC 的示例代码?
  • 这篇 Stackoverflow 帖子可以让您深入了解您的警告:Warning when using react hooks in HoC。附带说明一下,创建 Hook 是为了在一定程度上替代 HOC,因此请考虑将 WithErrorHandler 改为自定义钩子的方法

标签: reactjs react-hooks


【解决方案1】:

您需要这些效果在返回的组件中运行吗?一种解决方案是将所有的钩子移到 Wrapping 组件中:

import React, { useState, useEffect } from 'react'
import Modal from '../../components/UI/Modal/Modal'

const WithErrorHandler = (WrappedComponent, axios) => {
  const [error, seterror] = useState(null)

  useEffect(() => {
    const resInterceptor = axios.interceptors.response.use(
      (res) => res,
      (error) => {
        seterror(error)
      },
    )

    const reqInterceptor = axios.interceptors.request.use((req) => {
      seterror(null)

      return req
    })

    return () => {
      axios.interceptors.request.eject(reqInterceptor)
      axios.interceptors.response.eject(resInterceptor)
    }
  }, [axios.interceptors.request, axios.interceptors.response])

  return (props) => {
    const errorConfirmedHandler = () => {
      seterror(null)
    }

    return (
      <>
        <Modal show={error} modalClosed={errorConfirmedHandler}>
          {error ? error.message : null}
        </Modal>
        <WrappedComponent {...props} />
      </>
    )
  }
}

export default WithErrorHandler

或者,您可以将该回调转换为自己的组件:

import React, { useState, useEffect } from 'react'
import Modal from '../../components/UI/Modal/Modal'

const WithErrorHandler = (WrappedComponent, axios) => (props) => (
  <Wrapped {...props} axios={axios} WrappedComponent={WrappedComponent} />
)

const Wrapped = ({ axios, WrappedComponent, ...props }) => {
  const [error, seterror] = useState(null)

  const resInterceptor = axios.interceptors.response.use(
    (res) => res,
    (error) => {
      seterror(error)
    },
  )

  const reqInterceptor = axios.interceptors.request.use((req) => {
    seterror(null)

    return req
  })

  useEffect(() => {
    return () => {
      axios.interceptors.request.eject(reqInterceptor)
      axios.interceptors.response.eject(resInterceptor)
    }
  }, [axios.interceptors.request, axios.interceptors.response, reqInterceptor, resInterceptor])

  const errorConfirmedHandler = () => {
    seterror(null)
  }

  return (
    <>
      <Modal show={error} modalClosed={errorConfirmedHandler}>
        {error ? error.message : null}
      </Modal>
      <WrappedComponent {...props} />
    </>
  )
}

export default WithErrorHandler

【讨论】:

  • 第二个似乎工作没有错误,但在基于类的一个中,如果我弄乱了 firebase url,它会显示来自这个组件的弹出窗口,但是当我使用第二个时,它刚刚显示一个空白页,是我的实现有问题吗?
猜你喜欢
  • 1970-01-01
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-27
  • 1970-01-01
相关资源
最近更新 更多