react 18 + antd5 + react-router-dom + react-activation 入坑

1,946 阅读2分钟

使用新版本的技术框架遇到哪些坑点?

  • antd 5 更新那些新的玩法 ?
  • react-activation 组建缓存遇到那些问题点?
  • react-router-dom 新的使用方法 ?

antd 5 更新那些新的玩法 ?

1) 目前体验最深度的就是css-in-js 这个功能,所有样式功能全部使用js编写了,不需要进行less,sass进行预编译功能了,在设定主题整体样式确实比以前多元化了功能。

2)自己项目怎么编写利用antd存在的css-in-js编写css代码?我这结合总结了一下 需要一下功能,上伪代码!

import { ConfigContext } from 'antd/es/config-provider'
import { useStyleRegister } from '@ant-design/cssinjs'
import type { CSSInterpolation } from '@ant-design/cssinjs'
import { DerivativeToken } from 'antd/es/theme/internal'
const getDemoStyle = (
 [theme, token, hashId]: any,
 prefixCls: string
) => {
 const wrapSSR = useStyleRegister(
   { theme, token, hashId, path: [prefixCls] },
   () => [genDemoStyle(prefixCls, token, hashId)]
 )
 return wrapSSR
}

const genDemoStyle = (
 prefixCls: string,
 token: DerivativeToken,
 hashId: string
): CSSInterpolation => {
 return [
   {
     [`.${prefixCls}`]: {
      coloe:'red'
     },
   },
 ]
}

const Demo = () =>{
   const { getPrefixCls } = React.useContext(ConfigContext)
   const prefixCls = getPrefixCls('csp-header')
   const [theme, token, hashId] = useToken()
   const demo = getLayoutHeaderStyle([theme, token, hashId], prefixCls)
   retuen demo(
    <div className={classNames(prefixCls, hashId, className)}>112121212</div>
   )

}

如图出现样式 image.png

还有一个在开发过程中css代码不提示就比较伤心,这个是其实vscode是提供了插件的css-in-js会有代码提示,这样就可以开心的玩耍了。

3)以上功能玩的是很开心,发现一些功能在360,qq等浏览器里面样式会出现问题,解决方案如下!

import {
 StyleProvider,
 legacyLogicalPropertiesTransformer,
} from '@ant-design/cssinjs'

const Demo =()=>{
 return ( 
   <StyleProvider
       hashPriority="high"
       transformers={[legacyLogicalPropertiesTransformer]}
     >
     
   </ConfigProvider>
  )
}
  

以上就是解决兼容性问题,去掉:where 这伪类方法,还有一种就是我们自己代码里面也会出现一些兼容性代码需要出来比如gap,import detectFlexGapSupported from 'antd/es/_util/hooks/useFlexGapSupport' 在antd里面提供了这个方法,可以判断。 。

4) App包裹组件

新的包裹组件,提供重置样式和提供消费上下文的默认环境。

何时使用

  • 提供可消费 React context 的 message.xxxModal.xxxnotification.xxx 的静态方法,可以简化 useMessage 等方法需要手动植入 contextHolder 的问题。
  • 提供基于 .ant-app 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
const { message } = App.useApp()

在组建里面这么使用

5)国际化的坑

import { App, ConfigProvider, DatePicker } from 'antd'
import zhCN from 'antd/locale/zh_CN'
import moment from 'moment'
import 'moment/locale/zh-cn'
moment.locale('zh-cn')
function Root() {
 return (
       <ConfigProvider
         locale={zhCN}
       >        </ConfigProvider>

 )
}

需要moment来解决一下

react-router-dom 新的使用方法 ?

1)升级之后不能使用react-loadable,那这个时候会出现不能动态加载组件,其实react 提供了原生方法

import { Result, Spin } from 'antd'
import React from 'react'
import KeepAlive from 'react-activation'
const MODE = process.env.NODE_ENV
class AsyncComponent extends React.Component<any> {
  constructor(props: any) {
    super(props)
  }
  componentDidCatch(error: any, info: any) {
    if (error && MODE != 'development') {
      window.location.reload()
    }
    console.log('error', error)
    console.log('info', info)
  }

  render() {
    const { componentName } = this.props
    const CompontentsImport = import(
      /* webpackPrefetch: true */ `@/views/${componentPath}/index.tsx`
    )
    if (!CompontentsImport) {
      console.error(`${componentName} is not found`)
      return (
        <div
          style={{
            height: '100%',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
          }}
        >
          <Result
            status="404"
            title="404"
            subTitle={`Sorry, ${componentName} is not found`}
          />
        </div>
      )
    }
    const Compontents = React.lazy(() => CompontentsImport as any)

    return (
      <React.Suspense
        fallback={
          <div
            style={{
              height: '100%',
              top: '50%',
              left: '50%',
              position: 'absolute',
            }}
          >
            <Spin tip="页面初始加载中..." />
          </div>
        }
      >
        <Compontents />
      </React.Suspense>
    )
  }
}
export { AsyncComponent }

配合路由编写,react路由新的方式分为2种,一个是json配合hook组件方式,我这边没有去使用,我使的方式如下

<Router>
    <Routes>
      <Route
        path="/demo"
        element={<AsyncComponent componentName="Demo" />}
      />
     
    </Routes>
   </Router>

在新的路由里面很多hook方法变了,最明显的是路由跳转方式变了,还有 Switch 变成了RouteswithRouter 去掉了,不过可以自己封装一个,把hook函数通过高阶组件方式

react-activation 组建缓存遇到那些问题点?

1)react-activation 对 react 18 支持有点问题,需要使用react17 的方式运行react 18

注意
  • 不要使用 <React.StrictMode /> 严格模式
  • (React v18+) 不要使用 ReactDOMClient.createRoot, 而是使用 ReactDOM.render组建库位置
import KeepAlive from 'react-activation'
import { useLocation } from 'react-router-dom'

function container(WrappedFunc: any) {
 return function (props: any) {
   const location = useLocation() //不要删除
   const path = window?.location?.pathname + window?.location?.search
   
   return (
     <KeepAlive cacheKey={path} name={path} autoFreeze={false}>
       <div >
         <WrappedFunc {...props} />
       </div>
     </KeepAlive>
   )
 }
}
export default container
import { AliveScope } from 'react-activation'
function Root() {
 return (
   <AliveScope>
     ....
   </AliveScope>
 )
}

还要再根目录添加 AliveScope 这个组件, 我这边编写一个高阶函数这样使用,也可以不需要用 react17 方式运行 (不过需要注意点事是,不能触发重新生成路由) 因为每次的React.lazy 都是重新生成组件,所以会跟缓存匹配不上,场景就是动态生成路由会出现。