React使用injectIntl封装高阶组件后报错Cannot call a class as a function
问题原因
报错的核心原因是injectIntl高阶组件的使用位置错误:
injectIntl的作用是接收一个React组件,返回一个注入了intl属性的新类组件- 你直接将
withCheckCountry这个高阶函数(本身不是React组件,是用来生成组件的函数)用injectIntl包裹,导出的就是一个类组件 - 路由配置中你调用
withCheckCountry(CountryApp, availableCountry, loadingCountry)相当于把类组件作为普通函数执行,直接触发Cannot call a class as a function报错
解决方案
方案1:调整injectIntl包裹位置(兼容原有写法)
将injectIntl从包裹外层高阶函数,改为包裹高阶函数返回的内层业务组件,同时从props中获取注入的intl对象,修正后的代码如下:
import React, {useState, useEffect} from 'react'; import PropTypes from 'prop-types'; import { Redirect } from 'react-router-dom'; import { toast } from 'react-toastify'; import ToastBody from "components/toastBody/toast"; import { injectIntl } from "react-intl"; const withCheckCountry = (Component, availableCountry, loadingCountry) => { // 内层业务组件,从props获取intl const InnerComponent = ({intl, ...props}) => { if (!loadingCountry) { const { countryCode } = props.match.params; const isCountryExist = availableCountry.some( country => country.countryCode === countryCode.toLocaleUpperCase(), ); const [errorTitle, setErrorTitle] = useState(intl.formatMessage(messages.errorTitle)); const [countryNotExist, setCountryNotExist] = useState(intl.formatMessage(messages.countryNotExist)); useEffect(() => { setErrorTitle(intl.formatMessage(messages.errorTitle)); setCountryNotExist(intl.formatMessage(messages.countryNotExist)); }, [intl]); if (!isCountryExist) { toast(() => <ToastBody title={errorTitle} message={countryNotExist} />); return <Redirect to="/" />; } } return <Component {...props} />; }; // 仅对内层组件做intl注入 return injectIntl(InnerComponent); }; // 修正类型校验:availableCountry是数组不是对象 withCheckCountry.propTypes = { availableCountry: PropTypes.array, }; export default withCheckCountry;
方案2:使用useIntl Hook(更适配函数式组件)
如果项目使用的react-intl版本支持Hook,直接用useIntl可以避免高阶组件嵌套的问题,代码更简洁:
import React, {useState, useEffect} from 'react'; import PropTypes from 'prop-types'; import { Redirect } from 'react-router-dom'; import { toast } from 'react-toastify'; import ToastBody from "components/toastBody/toast"; import { useIntl } from "react-intl"; const withCheckCountry = (Component, availableCountry, loadingCountry) => { return ({...props}) => { // 直接用Hook获取intl对象 const intl = useIntl(); if (!loadingCountry) { const { countryCode } = props.match.params; const isCountryExist = availableCountry.some( country => country.countryCode === countryCode.toLocaleUpperCase(), ); const [errorTitle, setErrorTitle] = useState(intl.formatMessage(messages.errorTitle)); const [countryNotExist, setCountryNotExist] = useState(intl.formatMessage(messages.countryNotExist)); useEffect(() => { setErrorTitle(intl.formatMessage(messages.errorTitle)); setCountryNotExist(intl.formatMessage(messages.countryNotExist)); }, [intl]); if (!isCountryExist) { toast(() => <ToastBody title={errorTitle} message={countryNotExist} />); return <Redirect to="/" />; } } return <Component {...props} />; }; }; withCheckCountry.propTypes = { availableCountry: PropTypes.array, }; export default withCheckCountry;
内容的提问来源于stack exchange,提问作者Ala Ben Aicha
相关产品推荐
相关产品推荐

