记录关于reactjs
相关知识,中文文档
Reactjs
是一个用于构建用户界面的JavaScript
库,常用的脚手架有create react app
和Nextjs
;目前,我的大部分项目都是基于Nextjs
、MUI
+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
- 在
Nextjs
中使用Linguijs
国际化时,会出现一个Cannot process file /<path>.tsx: Duplicate declaration "Trans"
问题?解决办法Github-952,原因是Linguijs
在extract
阶段NODE_ENV
必须是development
。
在项目中npm i cross-env
,这个JS库
可以改变环境变量,然后在package.json
文件中,将extract
命令改为"extract": "cross-env NODE_ENV=development lingui extract --clean"
,就可以解决上述问题。
国际化配置文件
记录一下,Nextjs
国际化的过程。基础配置为Nextjs
、MUI
+TypeScript
。
版本,
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", } }
安装需要的模块
npm install --save-dev @lingui/cli @lingui/loader @lingui/macro babel-plugin-macros @babel/core npm install --save @lingui/react make-plural
配置
next.config.js
module.exports = { i18n: { locales: ["zh","en"], // 设置支持的语言 defaultLocale: "zh", // 默认语言 }, };
在项目根目录创建文件
.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
,这是推荐方式。
在根目录下,配置
.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"] } } }
在
package.json
文件中创建两个脚本命令,如下:{ "scripts":{ "extract":"cross-env NODE_ENV=development lingui extract --clean", "compile":"lingui compile" } }
cross-env
需要使用npm i cross-env
安装,为什么需要这个js
库,前面讲过。创建
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); }
在
_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> ) }
标记需要翻译的字段,有两种方式,可以配合着使用。
- 第一种
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> ) }
- 第一种
翻译,通过第9步,我们标记了需要翻译的字段,怎么翻译呢?在终端输入
npm run extract
;会出现如下的输出:┌─────────────┬─────────────┬─────────┐ │ Language │ Total count │ Missing │ ├─────────────┼─────────────┼─────────┤ │ zh (source) │ 5 │ - │ │ en │ 5 │ 5 │ └─────────────┴─────────────┴─────────┘
Language
:表示翻译语言的种类;Total count
:需要翻译的字段总数;Missing
:没有翻译的字段总是(可以看到en
,都没有翻译)。接下来就是手动翻译了,我还没有找到智能的翻译。到
.linguirc
文件中catalogs
的path
对应的文件中找到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 "关于"
我们将所有
po
文件中的msgstr
都翻译完成,可以使用npm run compile
,生成js
文件,在production
环境中使用。在页面中切换语言;我这里仅举例,在
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
使用服务端渲染,这个时候window
或document
是属于浏览器的属性,是没办法在服务端获得的。解决方法是使用动态导入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
构建镜像报错及解决方法
FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
解决方法: