Wangjili
文章58
标签12
分类9
reactjs

reactjs

记录关于reactjs相关知识,中文文档

Reactjs是一个用于构建用户界面的JavaScript库,常用的脚手架有create react appNextjs;目前,我的大部分项目都是基于NextjsMUI+TypeScript构建的,下面的内容主要是记录平时的开发。

一、一个根据用户名生成头像的库

@multiavatar/multiavatar在react中的使用

import React,{useEffect,useRef} from 'react';
import multiavatar from '@multiavatar/multiavatar';
const Example = ()=>{
	const svgRef = useRef();
	useEffect(()=>{
	let content = multiavatar("jack");
	svgRef.current.innerHTML = content
	},[])
	return (
		<div style={{width:"50px",height:"50px"}} ref={svgRef}> </div>
)
} 
export default Example;

二、React Fiber架构原理

文章:博客园-React Fiber 原理
React的渲染重绘采用一种Virtual DOM模式,其中非常重要的渲染算法就是React Fiber

三、Nextjs项目国际化

其实国际化就是配置多语种,对开发者来说,就是为项目配置多种语言的翻译。
参考文档:Linguijs官网react use Lingui.js

  1. Nextjs中使用Linguijs国际化时,会出现一个Cannot process file /<path>.tsx: Duplicate declaration "Trans"问题?解决办法Github-952,原因是Linguijsextract阶段NODE_ENV必须是development
    在项目中npm i cross-env,这个JS库可以改变环境变量,然后在package.json文件中,将extract命令改为"extract": "cross-env NODE_ENV=development lingui extract --clean",就可以解决上述问题。

国际化配置文件

记录一下,Nextjs国际化的过程。基础配置为NextjsMUI+TypeScript

  1. 版本,package.json

    {
        "dependencies":{
            "next": "12.1.6",
            "react": "18.1.0",
            "react-dom": "18.1.0",
            "@lingui/react": "^3.13.3",
            "make-plural": "^7.1.0",
        },
        "devDependencies":{
            "@lingui/cli": "^3.13.3",
            "@lingui/loader": "^3.13.3",
            "@lingui/macro": "^3.13.3",
        }
    }
  2. 安装需要的模块

    npm install --save-dev @lingui/cli @lingui/loader @lingui/macro babel-plugin-macros @babel/core
    npm install --save @lingui/react make-plural
  3. 配置next.config.js

    module.exports = {
        i18n: {
            locales: ["zh","en"],  // 设置支持的语言
            defaultLocale: "zh",  // 默认语言
        },
    };
  4. 在项目根目录创建文件.linguirc,输入如下内容

    {
        "locales": [
            "zh",
            "en"
        ],
        "sourceLocale": "zh",
        "fallbackLocales": {
            "default": "zh"
        },
        "catalogs": [
            {
                "path": "<rootDir>/src/translations/locale/{locale}/messages",
                "include": [
                    "<rootDir>/"
                ],
                "exclude": [
                    "**/node_modules/**"
                ]  
            }
        ],
        "format":"po"
    }
    • locales:国际化语言支持;
    • sourceLocale:源码使用的语言,这个指的是需要翻译的字段在源码中默认使用的语言;
    • fallbackLocales:当国际化失败时,返回的默认使用语言;
    • catelogs:翻译配置参数,包括path(翻译文件的保存路径)、include(需要翻译的文件目录,<rootDir>/是指项目中根目录下的所有文件)和exclude(需要翻译的文件目录)
    • format:翻译文件的保存格式,po指将翻译文件保存为xxx.po,这是推荐方式。
  5. 在根目录下,配置.babelrc文件,没有就创建,内容如下:

    {
        "presets": [
            [
                "next/babel",
                {
                    "preset-env": {},
                    "transform-runtime": {},
                    "styled-jsx": {},
                    "class-properties": {}
                }
            ]
        ],
        "plugins": [
            "macros",
            "@babel/plugin-syntax-dynamic-import",
            "@babel/plugin-proposal-class-properties"
        ],
        "env": {
            "test": { "plugins": ["dynamic-import-node"] }
        }
    }
  6. package.json文件中创建两个脚本命令,如下:

    {
        "scripts":{
            "extract":"cross-env NODE_ENV=development lingui extract --clean",
            "compile":"lingui compile"
        }
    }

    cross-env需要使用npm i cross-env安装,为什么需要这个js库,前面讲过。

  7. 创建i18n.ts文件,其实这个文件的位置和名称可根据个人喜好设置。我是放在src/lingui/i18n.ts这里。输入如下内容:

    import { i18n } from "@lingui/core";
    import { en, zh } from "make-plural/plurals";
    
    export const defaultLocale = "zh";
    
    
    i18n.loadLocaleData({ en: { plurals: en }, zh: { plurals: zh } });
    
    /**
    * Load messages for requested locale and activate it.
    * This function isn't part of the LinguiJS library because there're
    * many ways how to load messages — from REST API, from file, from cache, etc.
    */
    export async function activate(locale: string) {
        const { messages } = await import(
            `../translations/locale/${locale}/messages.js`  // 这里需要与 .linguirc 文件中 catalogs 的 path 对应
        );
        i18n.load(locale, messages);
        i18n.activate(locale);
    }
  8. _app.tsx文件中插入如下内容:

    import {  I18nProvider } from "@lingui/react";
    import { i18n } from '@lingui/core';
    
    import { activate,defaultLocale, } from "../src/lingui/i18n";
    
    export default function MyApp(props:MyAppProps){
        React.useEffect(()=>{
            activate(defaultLocale)
        },[])
    
        return (
            <I18nProvider i18n={i18n}>
                <Component {...pageProps} />
            </I18nProvider>
        )
    }
  9. 标记需要翻译的字段,有两种方式,可以配合着使用。

    • 第一种 Trans;
      import {Trans} from '@lingui/macro';
      export default function Demo(){
          return (
              <div>
                  <Trans> 需要翻译的字段 </Trans>
              </div>
          )
      }
    • 第二种 t;
      import {t} from '@lingui/macro';
      export default function Demot(){
          return (
              <div>
              {t`需要翻译的字段`}
              </div>
          )
      }
  10. 翻译,通过第9步,我们标记了需要翻译的字段,怎么翻译呢?在终端输入npm run extract;会出现如下的输出:

    ┌─────────────┬─────────────┬─────────┐
    │ Language    │ Total count │ Missing │
    ├─────────────┼─────────────┼─────────┤
    │ zh (source) │     5       │    -    │
    │ en          │     5       │    5    │
    └─────────────┴─────────────┴─────────┘
    

    Language:表示翻译语言的种类;
    Total count:需要翻译的字段总数;
    Missing:没有翻译的字段总是(可以看到en,都没有翻译)。

  11. 接下来就是手动翻译了,我还没有找到智能的翻译。到.linguirc文件中catalogspath对应的文件中找到xxx.po文件(这个第10步生成的),类似如下:

    #: pages/about.tsx:8
    #: pages/about.tsx:8
    #: src/components/common/Layout/Topbar.tsx:48
    msgid "About"
    msgstr ""
    • msgid:是翻译字段的ID,这个可以自定义,不一定和翻译字段相同;
    • msgstr:是需要我们自己翻译的,比如zh/message.po说明需要把该字段翻译为中文,这个需要自己填。建议找专业翻译人员翻译。我们可以把它改为关于,翻译后的如下:
      #: pages/about.tsx:8
      #: pages/about.tsx:8
      #: src/components/common/Layout/Topbar.tsx:48
      msgid "About"
      msgstr "关于"
  12. 我们将所有po文件中的msgstr都翻译完成,可以使用npm run compile,生成js文件,在production环境中使用。

  13. 在页面中切换语言;我这里仅举例,在index.tsx文件中,添加如下内容:

    import {activate} from '../src/lingui/i18n';  // 你自己 i18n.ts 的位置
    export default function IndexPage(){
        return (
            <div>
                <button onClick={() => activate("zh")}>中文</button>
                <button onClick={() => activate("en")}>英文</button>
            </div>
        )
    }

    至此,基本功能已全部实现。需要注意的是,需要将翻译字段写在组件内部,写在外部虽然不会报错,但是翻译不成功。
    补充:在实际开发中,常量一般会存放在独立的文件中.ts文件,这时候它会翻译不成功(前面说过),发现原因是:在切换语言时,虽然对应的语言包加载成功了,但是React.js在渲染页面时,并不会重新加载引入的常量。然后我想了一个解决办法,就是将保存常量的变量改为函数,这样在切换语言时,函数会被重新调用,从而成功翻译。

Next13启动报错

今天使用新版Nextjs开发项目,使用yarn dev启动项目时,报了一个错误SynaxError: Unexpected token '?',查询发现是node版本不对,升级到最新版就可以了。

Nextjs引入第三方库时报错ReferenceError: document is not defined

原因是Nextjs使用服务端渲染,这个时候windowdocument是属于浏览器的属性,是没办法在服务端获得的。解决方法是使用动态导入dynamic,如下:

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic( import('../components/hello'),{ssr:false})

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponent />
      <p>HOME PAGE is here!</p>
    </div>
  )
}

export default Home

四、docker构建镜像报错及解决方法

  1. FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
    解决方法:
本文作者:Wangjili
本文链接:https://blog.wangjili.cn/2023/01/02/reactjs/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可