关于react.js:reactantd使用RangePicker日期选择组件显示中文方案

1.开发环境 react2.电脑系统 windows11专业版3.废话不多说,间接上代码: // 无效的配置 : 能够显示为中文 <RangePicker picker="month" onChange={dateChange} /> 要害代码// 须要导入import 'moment/locale/zh-cn';//解决中文显示问题 !!!要害代码//成果如下图 //有效的配置:尝试应用 ConfigProvider 发现仍然是英文<ConfigProvider locale={zhCN}> <RangePicker value={zhCN} open /></ConfigProvider>//导入import zhCN from "antd/lib/locale/zh_CN"; //有效的配置4.本期的分享到了这里就完结啦,心愿对你有所帮忙,让咱们一起致力走向巅峰。

August 31, 2022 · 1 min · jiezi

关于react.js:usePolymerAction

背景随着React Hooks 遍及起来,组件逻辑写法变成函数式;逻辑函数申明、函数代码构造,随着逻辑减少简单,代码组织凌乱,函数申明散乱;最要害的一点,每个人对代码了解不一样,有的喜爱在一个function 写大段逻辑,有的喜爱拆分逻辑很细,就会使在我的项目保护时,代码格调、代码构造,越来越不对立,难以保护。针对上述情况,须要能够组织代码结、梳理逻辑的办法,从而达到我的项目维护性高、代码构造对立、逻辑清晰 设计理念 形象代码构造在编写代码的过程中,发现能够形象出公共代码构造; 申明可变数据/共享变量申明、state 申明/let xxx= xxx/useState办法申明/function xx () {} /action/dispatch办法调用 / xx() / action()/dispatch()通过上图,能够把常见组件外部逻辑,分成3个局部,其中3、4属于雷同局部: :次要是申明数据,有useState/let xxx = 11;:申明函数、办法,会波及批改数据**setcounts**、应用数据**sendLogcount**; 其中批改与应用里会有一些辅助办法fetch来执行对应逻辑;调用办法,3与4局部都在视图中应用函数与办法,对立称为调用办法。把代码构造拆分、剖析之后;其实在日常的开发过程中大部分代码简单逻辑都在1与2局部,而2局部里有互相调用的逻辑,各种辅助函数互相杂糅在一起,缓缓的使得代码越来越简单,难以浏览。 申明与定义咱们能够把1与2局部简单封装起来,定义好标准洁净的构造如依据上图可知,把原先1、2、3 局部对立封装在一个hooks.js文件里; 原先1与2局部代码通过调用**polymerAction**给聚合起来,把state与actions/办法申明给放在一起;再通过**const [state, actions, shareVars] = usePolymerActionState(countActions)**对外裸露数据与acions/办法。原先3局部封装hooks应用**usePolymerActionState**裸露办法调用,走失常调用逻辑。在视图里,失常应用hooks 封装办法,**return**出**usePolymerActionState**裸露数据与办法,失常调用逻辑。能够看出外围局部,就是把state与action封装在一起高内聚,通过对象组织代码构造,而对象能够进行组合形式,来组织更大简单的代码逻辑与构造。从视图上来看,只调用裸露进去的办法。总结一下,依照上述形式,能够进步我的项目可维护性,代码构造对立。 用法/** @jsx createElement */import { createElement, useEffect, useState, useRef, useMemo } from 'rax';import { moduleInit } from './utils';export default function Whrealtimetrendinghotels(props) { const { gdc, mds, pageUtils } = props; moduleInit({ gdc, mds, pageUtils })(useState, useEffect, useRef,useMemo); return (<CustomComponent />);}入口文件须要在moduleInit 传入useMemo,留神传入地位,间接依照上述地位传入即可。ps:为了兼容小程序,在小程序里,库不能间接引入import { createElement, useEffect, useState, useRef, useMemo } from 'rax'; ...

August 30, 2022 · 4 min · jiezi

关于react.js:React报错之Property-does-not-exist-on-type-JSXIntrinsicElements

注释从这开始~ 总览当组件名称以小写字母结尾时,会导致"Property does not exist on type 'JSX.IntrinsicElements'"谬误。为了解决该谬误,确保组件名称总是以大写字母结尾,装置React申明文件并重启你的开发服务器。 这里有个示例用来展现谬误是如何产生的。 // App.tsx// ️ name starts with lowercase letterfunction myComponent() { return <h1>Hello world</h1>;}function App() { return ( <div> {/* ⛔️ Property does not exist on type 'JSX.IntrinsicElements'. */} <myComponent /> </div> );}export default App;上述代码片段的问题在于,myComponent是以小写字母结尾的。 组件大写为了解决该问题,请确保所有的组件名称均以大写字母结尾。 // App.tsxfunction MyComponent() { return <h1>Hello world</h1>;}function App() { return ( <div> <MyComponent /> </div> );}export default App;React应用这种命名常规来辨别p、div、span等内置元素和咱们定义的自定义组件。 如果谬误仍未解决,尝试重启IDE和开发服务器。类型申明如果那都没有帮忙,确保装置了react的类型申明文件。在我的项目的根目录下关上终端,并运行上面的命令: # ️ with NPMnpm install --save-dev @types/react @types/react-dom# ----------------------------------------------# ️ with YARNyarn add @types/react @types/react-dom --dev如果谬误仍未解决,尝试删除node_modules以及package-lock.json(不是package.json)文件,从新运行npm install并重启IDE。 ...

August 30, 2022 · 1 min · jiezi

关于react.js:React报错之Property-value-does-not-exist-on-type-EventTarget

注释从这开始~ 总览当event参数的类型不正确时,会产生"Property 'value' does not exist on type EventTarget"谬误。为了解决该谬误,将event的类型申明为React.ChangeEvent<HTMLInputElement> 。而后就能够通过event.target.value 来拜访其值。 这里有个示例用来展现谬误是如何产生的。 // App.tsxfunction App() { // ️ incorrect event type const handleChange = (event: Event) => { console.log(event.target?.value); }; return ( <div> {/* ⛔️ Property 'value' does not exist on type 'EventTarget'. */} <input onChange={handleChange} type="text" id="message" /> </div> );}export default App;正确申明类型为了解决该谬误,咱们必须将event参数的类型申明为React.ChangeEvent<HTMLInputElement>。 // App.tsxfunction App() { // ✅ correct event type const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { console.log(event.target.value); }; return ( <div> <input onChange={handleChange} type="text" id="message" /> </div> );}export default App;React中的ChangeEvent类型有一个target属性,援用的是事件被派发的元素。 ...

August 29, 2022 · 1 min · jiezi

关于react.js:node-下载与上传文件

将node作为应用程序,从某个网站下载文件,而后将其上传到服务器上。 须要用到的库 axios:^0.27.2form-data:^4.0.0思路: 1.应用axios将文件下载下来,放在tmp文件夹下,responsetype设为arraybuffer,因为写文件writefilesync须要应用到arraybuffer,不要下载stream流,应用createwritestream写文件,因为你还须要把下载下来的文件从新上传,而createwritestream没有同步的办法,这会导致你再上传的时候,文件还没生成好,造成服务器无奈正确获取文件。 2.读取tmp文件夹下文件,应用axios上传即可 const axios = require('axios')const fs = require("fs");const path = require("path");const Formdata = require("form-data");const fileName = "";//文件名称const fileDownloadUrl = ""; //文件下载门路const fileUploadUrl = "";//文件上传门路async function downloadAndUpload() { let downloadResp = await axios({ method: "get", url: fileDownloadUrl, responseType: "arraybuffer" }) let tempFileDir = path.join(path.resolve(__dirname, "tmp"), fileName);//长期文件目录 fs.writeFileSync(tempFileDir, downloadResp.data); //同步写入临时文件 let formdata = new Formdata(); formdata.append("file", fs.createReadStream(tempfiledir)); let headers = formdata.getHeaders(); let uploadResp = await axios({ method: "post", url: fileUploadUrl, headers: headers, data: formdata, maxBodyLength: Infinity, }) return uploadResp;}

August 28, 2022 · 1 min · jiezi

关于react.js:React报错之Parameter-event-implicitly-has-an-any-type

注释从这开始~ 总览当咱们不在事件处理函数中为事件申明类型时,会产生"Parameter 'event' implicitly has an 'any' type"谬误。为了解决该谬误,显示地为event参数申明类型。比如说,在input元素上,将解决change事件申明类型为React.ChangeEvent<HTMLInputElement> 。 这里有个示例用来展现谬误是如何产生的。 // App.tsxfunction App() { // ⛔️ Parameter 'event' implicitly has an 'any' type.ts(7006) const handleChange = event => { console.log(event.target.value); console.log(event.target); }; return ( <div> <input onChange={handleChange} type="text" id="message" /> </div> );}export default App;示例中的问题在于,咱们没有显示地为事件处理函数的event参数申明类型。 设置类型为了解决该谬误,咱们必须依据事件类型为参数设置一个类型。 // App.tsxfunction App() { const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { console.log(event.target.value); console.log(event.target); }; return ( <div> <input onChange={handleChange} type="text" id="message" /> </div> );}export default App;咱们将事件的类型申明为React.ChangeEvent<HTMLInputElement> ,因为咱们正在为input元素申明一个onChange事件。 你要找出事件的类型,最简略的办法是将事件处理器内联编写,并将鼠标悬浮在函数的event参数上。 ...

August 28, 2022 · 2 min · jiezi

关于react.js:React报错之Parameter-props-implicitly-has-an-any-type

注释从这开始~ 总览当咱们没有为函数组件或者类组件的props申明类型,或遗记为React装置类型申明文件时,会产生"Parameter 'props' implicitly has an 'any' type"谬误。为了解决这个谬误,在你的组件中明确地为props对象设置一个类型。 装置类型文件你首先要确定的是你曾经装置了React类型申明文件。在我的项目的根目录下关上终端,并运行以下命令。 # ️ with NPMnpm install --save-dev @types/react @types/react-dom# ----------------------------------------------# ️ with YARNyarn add @types/react @types/react-dom --dev尝试重启你的IDE和开发服务。 申明类型如果这没有帮忙,你有可能遗记明确地为函数组件或类组件的props申明类型。 // App.tsx// ⛔️ Parameter 'props' implicitly has an 'any' type.ts(7006)function Person(props) { return ( <div> <h2>{props.name}</h2> <h2>{props.age}</h2> <h2>{props.country}</h2> </div> );}function App() { return ( <div> <Person name="James" age={30} country="Australia" /> </div> );}export default App;上述代码片段的问题在于,咱们没有为函数组件的props设置类型。 为了解决该谬误,咱们必须显示地props参数类型。 // App.tsxinterface PersonProps { name: string; age: number; country: string; children?: React.ReactNode; // ️ for demo purposes}function Person(props: PersonProps) { return ( <div> <h2>{props.name}</h2> <h2>{props.age}</h2> <h2>{props.country}</h2> </div> );}function App() { return ( <div> <Person name="James" age={30} country="Australia" /> </div> );}export default App;咱们为组件的props显示地申明了一个接口,这就能够解决谬误。 ...

August 27, 2022 · 2 min · jiezi

关于react.js:React报错之Property-value-does-not-exist-on-type-HTMLElement

注释从这开始~ 总览当咱们试图拜访一个类型为HTMLElement的元素上的value属性时,会产生"Property 'value' does not exist on type 'HTMLElement'"谬误。为了解决该谬误,在拜访属性之前,应用类型断言将元素类型断言为HTMLInputElement。 这里有个示例用来展现谬误是如何产生的。 // App.tsximport {useEffect} from 'react';export default function App() { useEffect(() => { const input = document.getElementById('message'); // ⛔️ Property 'value' does not exist on type 'HTMLElement'.ts(2339) console.log(input?.value); }, []); return ( <div> <input id="message" defaultValue="Initial value" /> </div> );}咱们失去谬误的起因是因为,document.getElementById办法返回的类型为HTMLElement | null ,并且value属性不存在于HTMLElement类型上。 类型断言为了解决该谬误,应用类型断言将元素类型断言为HTMLInputElement(或者HTMLTextAreaElement,如果你应用textarea元素键入)。 import {useEffect} from 'react';export default function App() { useEffect(() => { // ✅ type element as HTMLInputElement const input = document.getElementById('message') as HTMLInputElement; console.log(input?.value); // ️ "Initial value" }, []); return ( <div> <input id="message" defaultValue="Initial value" /> </div> );}你也能够在内联中应用一个类型断言,就在拜访值属性之前。 ...

August 26, 2022 · 2 min · jiezi

关于react.js:react状态总结

本文从动机脉络聊聊对react生态中的状态相干技术的演化过程。 集体了解,欢送探讨响应式渲染框架这里只聊react的状态和视图渲染相干内容,不聊底层的Virtual DOMreact是一个mvvm框架,作为一个响应式渲染设计,当本身的模型(状态)发生变化时,会主动刷新(re-render)以后视图显示最新的模型(状态)数据。 那是如何监听状态发生变化呢?react本着极简的api设计理念,遵循函数式编程中的不可变对象理念,对于状态实现的特地简略,只提供了一个setStateAPI。在react组件中,须要视图发生变化时,只须要对调用setState进行数据时图进行扭转,就会触发以后组件的re-render,实现更新。所以此时能够了解为,react是响应式设计的渲染框架,但其状态不是响应式模式,是一个命令式状态框架。如上面的代码: class Page extends React.Component<{}, {no: number}> { constructor() { super({}); this.state = { no: 0, }; } render() { console.log('render执行'); return <h1 onClick={() => { this.setState({ no: 0 }); }}>Hello, {this.state.no}</h1>; }}当执行setState时,尽管状态no前后都是0, 然而组件的render还是会被从新执行。 这样简略的设计,既是react的长处又是react的毛病。长处是react只提供最底层的状态更新api, 使用者能够应用市面上任意的其余状态框架,整个框架不显得轻便。毛病就是不能开箱即用,减轻使用者心智累赘。 react中的单向数据流设计,在整个组件树中,只容许状态从头流到叶子节点的起因是什么呢?这是因为每一个组件的子节点都是执行在render函数中,相似于一个递归树。当以后组在re-render时,就会从新调用子节点从新执行render,也就整个以后组件以下的整个组件都会re-render。所以当只有父向子的单向数据流时,这个调用流程只须要调用一次就能够把以后变动后的数据“响应”到视图上。代码成果: const Foo: React.FC<Record<string, unknown>> = () => { console.log('Foo被从新渲染了'); return ( <div> Foo </div> );}const Bar: React.FC<Record<string, unknown>> = () => { console.log('Bar被从新渲染了'); return ( <div> Bar </div> );}class Parent extends React.Component { constructor() { super({}); this.state = { no: 0, }; } render() { console.log('Parent被从新渲染了'); return ( <div onClick={() => this.setState((preState) => ({ no: preState.no + 1 }))}> <Foo /> <Bar /> </div> ); }}当Parent中的状态发生变化时,会发现Parent, Foo, Bar组件都产生了re-render。 ...

August 26, 2022 · 4 min · jiezi

关于react.js:React报错之You-provided-a-checked-prop-to-a-form-field

注释从这开始~ 总览当咱们在多选框上设置了checked 属性,却没有onChange 处理函数时,会产生"You provided a checked prop to a form field without an onChange handler"谬误。为了解决该谬误,能够应用defaultChecked 属性,或者在表单字段上设置onChange 属性。 这里有个例子用来展现谬误是如何产生的。 // App.jsexport default function App() { // ⛔️ Warning: You provided a `checked` prop to a form field // without an `onChange` handler. This will render a read-only field. // If the field should be mutable use `defaultChecked`. // Otherwise, set either `onChange` or `readOnly`. return ( <div> <input type="checkbox" id="subscribe" name="subscribe" checked={true} /> </div> );}上述代码片段的问题在于,咱们在input表单上设置了checked属性,但却没有提供onChange事件处理器。这使得input的checked属性成为动态的。 ...

August 25, 2022 · 2 min · jiezi

关于react.js:不容错过什么是领域驱动设计为什么落地这么难

引言 畛域驱动设计并不是新的架构设计实践,从 Eric Evans 提出至今曾经有十多年历史。因为微服务架构的衰亡,DDD 罕用于领导微服务边界划分,并从新宽泛进入软件研发公众的视线。DDD 的理念及利用遍及在国外绝对成熟,在国内尚处于初期倒退阶段。国内的很多社区以及企业组织外部近几年对于 DDD 的探讨和利用逐步炽热,许多架构师以及开发人员对 DDD 充斥了学习和实际的激情。而像麻利一样,不同团队对其认知程度和实际程度不尽相同,有的胜利,大多数可能是失败的。 畛域驱动设计(Domain Driven Design),简称 DDD, Eric Evans 2004 年的《Domain-Driven Design: Tackling Complexity in the Heart of Software》一书中第一次提出。畛域驱动设计是一种用于领导软件设计的方法论,也是一种设计思维形式,用于解决软件复杂性问题,旨在减速那些必须解决简单畛域的软件我的项目的开发。 实际 DDD 的第一步不在于如何编写代码,而首先须要拉齐对畛域驱动设计的认知。后续的系列文章将围绕畛域驱动设计进行不同视角探讨,以期帮忙大家对其有更深刻的意识,并能利用的理论的研发工作中。 聊聊问题空间、解空间、畛域模型 问题空间和解决方案空间 问题空间:Problem Space,是以后环境下业务所面临的一系列问题和问题背地的需要,通常是业务和产品领域专家主导问题、需要的收集形容和剖析。问题空间框定了咱们要解决的问题的上下文,这种上下文环境不是软件工程或是畛域驱动所独有的,而是通用的共性的元素。工程实际必然处于某种上下文环境之下。 解决方案空间:Solution Space,解决方案空间是针对问题空间的解决方案,属于工程实现阶段,由技术专家主导方案设计。 软件开发过程,实质上能够看作是问题空间到解决方案空间的一个映射转化:问题空间,找出业务挑战及其对相干需要场景用例剖析解空间,通过具体的技术工具伎俩来进行设计实现 畛域、模型和畛域模型 畛域:Domain “畛域” 是 “常识或流动的汇合”,绝对于软件系统而言,畛域就是软件应用所要解决的事实问题区域。畛域对应于问题空间,是一个特定范畴边界内的业务需要的总和。 畛域模型:Domain Model 形象是一种化繁为简的能力,是人类意识世界的利器,也是一种生物本能。在无限的脑容量的前提下,人类不可能存储记忆所有的细节,海量信息曾经超出人脑存储限度而无奈包容和无效获取。形象使得人类能够屏蔽无关细节信息,抽取高层的无效信息进行记忆存储。试想,如果脑机接口技术有所突破,在人脑背地链接的是海量的高效的计算机集群,这种有限的存储、计算和检索能力的加强,“形象能力兴许会被弱化”。 模型被用来表述人们所关注的事实或想法的某个方面,实质上是一种形象过程的产物,把与解决方案密切相关的方面形象进去,而疏忽无关细节。 聚焦在软件工程畛域,要想构建满足需要的软件系统,开发团队须要软件面向的畛域所波及的常识可能十分宏大和简单,而模型正是解决这种信息超载问题的无效工具。 对畛域进行模型设计的过程就是领域建模,领域建模的目标并非是要建设一个百分之百合乎 “事实” 的模型,实践上,咱们也无奈实现这种对事实的齐全建模,而只能是对事实某种程度的模仿。 领域建模的输入即畛域模型,畛域模型是针对特定畛域里的要害事物及其关系的可视化体现,属于解决方案空间领域。为了精确定义须要解决问题而结构的形象模型,为软件系统的构建指标对立认知,是业务性能场景在软件系统里的映射转化。畛域模型并非领域专家头脑中的常识,而是对这些常识进行严格的组织和有抉择的形象。 同时,畛域模型并非某种非凡的图、文字或者代码,而是他们所传播的思维,图、文字或代码都能够作为模型的示意或传播模式,但他们不是模型,而是不同维度的模型视图。 畛域驱动设计 畛域驱动设计强调畛域模型的重要性,并通过模型驱动设计来保障畛域模型与程序设计的统一。畛域驱动设计首先从业务需要中提炼出对立语言,并建设畛域模型领导着程序设计以及编码实现;最初,又通过重构来发现隐式概念,并一直解决畛域畛域模型相干的新问题。实质上,畛域驱动设计也是从问题空间映射到解决方案空间。 畛域驱动设计联合了宏观和宏观两个层面的设计,别离对应于畛域驱动概念中的策略设计和战术设计。 畛域驱动设计:策略设计 策略设计的初衷是要放弃模型的完整性,次要从上面两个方面来考量的: 问题域方面:将问题规模进行拆解,划分为不同类型的子域,辨认出外围畛域与其余子畛域。解决方案层面:划分限界上下文和上下文映射对问题域进行正当的合成,确定上下文边界以及它们之间的关系。 畛域驱动设计:战术设计 策略设计的初衷是要放弃模型的完整性,通过策略设计将整个软件系统合成为多个限界上下文,而后对每个界线上下文进行战术设计。对每个限界上下文进行战术设计。Eric Evans 提供的模型驱动设计的结构因素以及因素间的关系如下图所示: 实体:Entity,不同于通过属性进行定义的传统对象,实体对象通过惟一标识进行辨别,且具备继续的生命周期。值对象:Value Object,值对象是具备属性且不可变的对象,但没有惟一标识。畛域事件:Domain Event,畛域事件用于记录零碎内的模型流动相干的离散事件,尽管零碎内所有事件都应该可能被跟踪,但只有被领域专家关怀的事件类型才创立畛域事件。聚合:Aggregate,聚合对象是实体和值对象的聚合,聚合具备一个惟一的根,即聚合根。内部对象不再间接拜访聚合外部的单个对象或者实体,而是间接拜访聚合根,并应用聚合根将指令传递给对应的分组。畛域服务:Domain Service,某些畛域逻辑不适宜调配给某个特定的实体对象,可将其这些操作封装成畛域服务资源库:Repositories,资源库不是配置库,它提供一个全局接口来拜访特定聚合外部所有的实体类和值对象,应该包含创立,批改,删除聚合外部对象的办法。工厂:Factories,工厂封装了创立简单对象和聚合的逻辑,对客户端屏蔽创立的复杂性上述 DDD 战术设计的模式标识了进行设计时的一些要害模式,但并非说是肯定要严格应用和遵循的,也不是遵循了所有的战术设计模式就是合乎畛域驱动设计。因为,实际 DDD 要害不在于这种战术层面模式的落地,而是在于其宏观的畛域驱动设计思维的遵循,比方对立语言、畛域模型与代码间的统一、子域及上下文的拆分以及映射、畛域模型与技术关注点的拆散等等。另外,随着 DDD 的一直倒退,一些新的构建模式曾经涌现,老的结构模型不肯定能合乎团队研发的要求。 ...

August 25, 2022 · 1 min · jiezi

关于react.js:React报错之Invalid-hook-call

注释从这开始~ 总览导致"Invalid hook call. Hooks can only be called inside the body of a function component"谬误的有多种起因: react和react-dom的版本不匹配。在一个我的项目中有多个react包版本。试图将一个组件作为一个函数来调用,例如,App()而不是<App />。在类外面应用钩子,或者在不是组件或自定义钩子的函数中应用钩子。 版本匹配在我的项目的根目录下关上终端,更新react和react-dom包的版本,确保版本是相匹配的,并且没有应用过期的版本。 # ️ with NPMnpm install react@latest react-dom@latest# ️ ONLY If you use TypeScriptnpm install --save-dev @types/react@latest @types/react-dom@latest# ----------------------------------------------# ️ with YARNyarn add react@latest react-dom@latest# ️ ONLY If you use TypeScriptyarn add @types/react@latest @types/react-dom@latest --dev如果谬误仍存在,尝试删除node_modules以及package-lock.json(不是package.json)文件,从新运行npm install 并重启你的IDE。 这个谬误通常是因为在同一个我的项目中领有多个版本的react造成的。 # ️ delete node_modules and package-lock.jsonrm -rf node_modulesrm -f package-lock.json# ️ clean npm cachenpm cache clean --forcenpm install如果谬误依然存在,请确保重启了IDE和开发服务。VSCode经常出现故障,须要重启。调用组件这里有另一个示例,用来展现谬误是如何产生的。 ...

August 24, 2022 · 2 min · jiezi

关于react.js:微模块前端业务模块化探索拆解巨石应用的又一利器

大家好,我是Eluxjs的作者,Eluxjs是一套基于“微模块”和“模型驱动”的跨平台、跨框架『同构计划』,欢送理解... 文前申明,以下推断和论断纯属集体摸索,鉴于自己常识程度所限,舛误在劫难逃,恳请各位大佬不吝赐教...什么是前端“微模块”?Elux中的『微模块』是指在Web前端工程中,将代码和相干资源依照不同的业务性能进行归类和模块化。 依据业务性能进行模块化始终以来都是后端的广泛做法,而Web前端则通常都是依照UI界面的视图区块View来进行模块化,这样的模块实际上只是Component组件,不具备独立自治的能力。究其原因我想是因为在晚期Web1.0的时代,前端的职能就是仅仅作为后端API数据的一个Render渲染器,所以前后端的视线和格局呈现了分化,也导致很多人说前端基本无架构之说。 然而web生态倒退到明天,浏览器越来越弱小,赋能越来越多,甚至不亚于一个小型操作系统,这时候的Web前端早已不是当初简略的数据渲染器,状态治理、会话维持、数据长久化、文件缓存、通信协议...随着PWA、小程序、快利用的推广,WebAPP不再是瘦客户端,慢慢成长为大胖小子。 此时的咱们该当跳出“渲染器”的井口,而从一个残缺的软件工程来思考咱们的前端架构,Web前端不只是一层View、一个GUI,咱们须要回归到与后端统一的以业务畛域为驱动的模块化视角。 为什么前端须要“微模块”?从开发角度来说:咱们须要高内聚、低耦合的涣散构造体,而不是牵一发而动全身的巨石利用,这不论是对于开发、保护、还是前期渐进式重构,都至关重要。 前端Leader:通过一年多的迭代和人员变动,咱们代码曾经凌乱不堪了,开发越来越吃力,必须要重构,否则玩不上来了!产品经理:嗯,我了解,这外面也有很多是咱们需要变更频繁引起的,我反对你们重构!前端Leader:感激大佬了解,那新需要先停下来,等咱们重构好了再迭代吧?产品经理:你们重构要多久?前端Leader:产品这么简单了,预计至多要3个月左右吧。产品经理被吓出一身冷汗:大佬,你要3天还能够思考,停下来3个月预计公司都要关门了...前端Leader:可是产品这么简单,几天工夫实现重构是天方夜谭。产品经理想了想:这样把,我每个迭代少安顿几个需要,这样你们每个月就能够留几天工夫重构了。前端Leader:这可不是1+1=2的问题,而是0与1的问题,大佬你不理解!产品经理:谁说我不理解,你们就不能渐进式重构吗?前端Leader:...此时如果咱们的前端工程是基于“微模块”,一来能够轻松的找到“部分重构”的边界,二来也能够通过维持“微模块”的对外接口来无极替换。 从产品角度来说:软件架构永远是服务于业务需要的。咱们心愿咱们的产品能像搭积木一样按需组合,能够疾速包装出各种灵活多样的套餐,以满足客户越来越精细化的定制需要。 某个大型利用蕴含A,B,C,D,E,F,G等若干性能,原来始终是整体打包发售...随着用户需要的多样化,有的用户仅须要局部性能,于是聪慧的前端架构师“小李”利用时下风行的微前端技术,将利用拆分成了的 3 个子利用:- 【根底利用】蕴含性能:A- 【子利用A】蕴含性能:B,C,D- 【子利用B】蕴含性能:E,F,G这样等于有 3 个套餐能够供客户抉择:- 套餐A:根底利用 + 子利用A- 套餐B:根底利用 + 子利用B- 套餐C:根底利用 + 子利用A + 子利用B然而用户的需要越来越精细化,有的须要ABCD,有的须要ACEG,有的须要ABDF...而且同一个性能可能还存在需要版本的不同,这让“小李”无可适从。当初咱们利用“微模块”来帮忙小李解决问题: 将各种独立的业务性能封装成不同的微模块:A,B,C,D,E,F,G将各种微模块按需要迭代版本,公布成NPM包某客户须要 A,C1(C性能的某个版本),E2(E性能的某个版本),G 性能,咱们独自为该客户创立一个聚合工程分支,装置相应版本的微模块:npm install A C@1 E@2 G 咱们晓得世界上有一款建站神器wordpress,已经号称世界上50%的网站都是由它创立的,我认为它的胜利秘诀就是社区模版机制和性能插件化,你要什么性能都总能找到“前端+后端”一起打包装置的插件,这也相似于“微模块”的概念。从工程的角度来说:“微模块”是跨工程、跨我的项目共享通用业务代码的现实决计划,对于跨端、跨平台复用业务逻辑尤其有用。 前端“微模块”的划分准则与边界领有高内聚、低耦合的工程构造。领有独立自治的子域逻辑。 从图中能够看到,每个微模块负责定义和保护本人畛域内的事务,并且麻雀虽小,五脏俱全,领有独立的路由解析、状态治理、数据模型、控制器、视图、组件、资源、业务实体、API治理等等...总之,所有与本人畛域相干的资源都被内聚到了一起。 以下是某巨石利用的SRC目录,其特点是以“文件职能”作为一级分类、“功能模块”作为次级分类: ├─ src│ ├─ api # API接口治理│ ├─ assets # 动态资源文件│ ├─ components # 全局组件│ ├─ config # 全局配置项│ ├─ enums # 我的项目枚举│ ├─ hooks # 罕用 Hooks│ ├─ language # 语言国际化│ ├─ layout # 框架布局│ ├─ routers # 路由治理│ ├─ store # store│ ├─ styles # 全局款式│ ├─ typings # 全局 ts 申明│ ├─ utils # 工具库│ ├─ views # 我的项目所有页面│ ├─ App.vue # 入口页面│ └─ main.ts # 入口文件以下是Elux中基于微模块的SRC目录,其改良是将“功能模块”作为一级分类,“文件职能”作为次级分类: ...

August 24, 2022 · 1 min · jiezi

关于react.js:React报错之React-hook-useState-cannot-be-called

注释从这开始~ 总览当咱们尝试在类组件中应用useState 钩子时,会产生"React hook 'useState' cannot be called in a class component"谬误。为了解决该谬误,请将类组件转换为函数组件。因为钩子不能在类组件中应用。 这里有个例子用来展现谬误是如何产生的。 // App.jsimport {useState, useEffect} from 'react';class Example { render() { // ⛔️ React Hook "useState" cannot be called in a class component. // React Hooks must be called in a React function component or a custom React Hook function. const [count, setCount] = useState(0); // ⛔️ React Hook "useEffect" cannot be called in a class component. // React Hooks must be called in a React function component or a custom React Hook function. useEffect(() => { console.log('hello world'); }, []); return ( <div> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }}导致这个谬误的起因是,钩子只能在函数组件或自定义钩子中应用,而咱们正试图在一个类中应用钩子。函数组件解决该谬误的一种办法是,将类组件转换为函数组件。 ...

August 23, 2022 · 1 min · jiezi

关于react.js:React报错之React-Hook-useEffect-is-called-in-function

注释从这开始~ 总览为了解决谬误"React Hook 'useEffect' is called in function that is neither a React function component nor a custom React Hook function",能够将函数名的第一个字母大写,或者应用use作为函数名的前缀。比如说,useCounter使其成为一个组件或一个自定义钩子。 这里有个示例用来展现谬误是如何产生的。 // App.jsimport React, {useEffect, useState} from 'react';// ️ Not a component (lowercase first letter)// not a custom hook (doesn't start with use)function counter() { const [count, setCount] = useState(0); // ⛔️ React Hook "useEffect" is called in function "counter" that // is neither a React function component nor a custom React Hook function. // React component names must start with an uppercase letter. // React Hook names must start with the word "use". useEffect(() => { console.log(count); }, [count]); return ( <div> <h2>Count: {count}</h2> <button onClick={() => setCount(count + 1)}>Increment</button> </div> );}上述代码片段的问题在于,咱们在一个函数中应用了useEffect钩子,而这个函数不是一个组件,因为它以小写字母结尾,也不是一个自定义钩子,因为它的名字不是以use结尾。 ...

August 22, 2022 · 2 min · jiezi

关于react.js:React报错之React-hook-useState-is-called-conditionally

注释从这开始~ 总览当咱们有条件地应用useState钩子时,或者在一个可能有返回值的条件之后,会产生"React hook 'useState' is called conditionally"谬误。为了解决该谬误,将所有React钩子移到任何可能油返回值的条件之上。 这里有个例子用来展现谬误是如何产生的。 import React, {useState} from 'react';export default function App() { const [count, setCount] = useState(0); if (count > 0) { return <h1>Count is greater than 0</h1>; } // ⛔️ React Hook "useState" is called conditionally. //React Hooks must be called in the exact same order // in every component render. Did you accidentally call // a React Hook after an early return? const [message, setMessage] = useState(''); return ( <div> <h2>Count: {count}</h2> <button onClick={() => setCount(count + 1)}>Increment</button> </div> );}上述代码片段的问题在于,咱们应用的第二个useState钩子,位于可能有返回值的条件之后。 ...

August 21, 2022 · 2 min · jiezi

关于react.js:react-react中的虚拟dom和真实dom对比

编写一下代码来看一下两者的异同: <body> <div id="demo"></div> <!-- 引入react外围库 --> <script type="text/javascript" src="js/react.development.js"></script> <!-- 引入react-dom,用于反对react操作dom --> <script type="text/javascript" src="js/react-dom.development.js"></script> <!-- 引入babel,用于将jsx转为js --> <script type="text/javascript" src="js/babel.min.js"></script> <script type="text/babel"> // 创立一个虚构dom const VDOM =( <h1 id="title"> <span>Hello,React</span> </h1> ) // 获取实在dom const TDOM= document.getElementById('demo'); console.log(typeof VDOM); console.log(typeof TDOM); console.log((typeof VDOM) === (typeof TDOM)); console.log(`虚构DOM:`,VDOM); console.log(`实在DOM:`, TDOM); debugger </script></body>输入:能够看出虚构DOM和实在DOM一样实质是Object类型对象 两者具体构造:显然实在DOM比虚构DOM身上多很多货色,这是因为虚构DOM是React外部应用,外面次要蕴含React须要的内容,而无关货色被去除。

August 21, 2022 · 1 min · jiezi

关于react.js:React报错之React-Hook-useEffect-has-a-missing-dependency

注释从这开始~ 总览当useEffect钩子应用了一个咱们没有蕴含在其依赖数组中的变量或函数时,会产生"React Hook useEffect has a missing dependency"正告。为了解决该谬误,禁用某一行的eslint规定,或者将变量挪动到useEffect钩子内。 这里有个示例用来展现正告是如何产生的。 // App.jsimport React, {useEffect, useState} from 'react';export default function App() { const [address, setAddress] = useState({country: '', city: ''}); // ️ objects/arrays are different on re-renders const obj = {country: 'Chile', city: 'Santiago'}; useEffect(() => { setAddress(obj); console.log('useEffect called'); // ⛔️ React Hook useEffect has a missing dependency: 'obj'. // Either include it or remove the dependency array. eslintreact-hooks/exhaustive-deps }, []); return ( <div> <h1>Country: {address.country}</h1> <h1>City: {address.city}</h1> </div> );}上述代码片段的问题在于,咱们在useEffect钩子外部应用了obj变量,但咱们没有在其依赖数组中蕴含该变量。 ...

August 20, 2022 · 3 min · jiezi

关于react.js:React报错之Expected-an-assignment-or-function

注释从这开始~ 总览当咱们遗记从函数中返回值时,会产生"Expected an assignment or function call and instead saw an expression"谬误。为了解决该谬误,确保显式地应用return语句或应用箭头函数隐式返回。 上面有两个示例来展现谬误是如何产生的。 // App.jsconst App = props => { const result = ['a', 'b', 'c'].map(el => { // ⛔️ Expected an assignment or function call and instead saw an expression. eslint no-unused-expressions el + '100'; }); return <div>hello world</div>;};const mapStateToProps = (state) => { // ⛔️ Expected an assignment or function call and instead saw an expression. eslint no-unused-expressions todos: ['walk the dog', 'buy groceries']}export default App;在App组件中,谬误是在Array.map()办法中引起的。这里的问题在于,咱们没有从传递给map()办法的回调函数中返回任意值。 ...

August 19, 2022 · 2 min · jiezi

关于react.js:React报错之Unexpected-default-export-of-anonymous-function

注释从这开始~ 总览当咱们尝试应用默认导出来导出一个匿名函数时,会导致"Unexpected default export of anonymous function"正告。为了解决该谬误,在导出函数之前,为函数赋予一个名称。 这里有个例子来展现正告是如何产生的。 // Header.js// ️ default export for anonymous function// ⛔️ Unexpected default export of anonymous function// eslint import/no-anonymous-default-exportexport default function () { return <h1>hello world</h1>;}上述代码的问题在于,咱们应用默认导出来导出一个匿名函数。 命名为了解决该谬误,在导出函数之前,为函数赋予一个名称。 // Header.js// ️ give name to function that's being exportedexport default function Header() { return <h1>hello world</h1>;}很重要:如果你要导出一个变量(或一个箭头函数)来作为默认导出,你必须在一行中申明它,在下一行中导出它。你不能在同一行中申明和默认导出一个变量。 // Header.jsconst Header = () => { return <h1>hello world</h1>;};export default Header;当初你依然可能应用默认导入来导入函数。 // App.jsimport Header from './Header';const App = () => ( <div> <Header /> </div>);export default App;这种办法激励在导出函数和导入函数时重复使用同一个标识符。默认状况下,eslint规定会正告咱们所有类型的匿名默认导出,例如数组、函数、类、对象等等。 ...

August 18, 2022 · 1 min · jiezi

关于react.js:React报错之Expected-onClick-listener-to-be-a-function

注释从这开始~ 总览当咱们为元素的onClick属性传递一个值,然而该值却不是函数时,会产生"Expected onClick listener to be a function"报错。为了解决该报错,请确保只为元素的onClick属性传递函数。 这里有个例子来展现谬误是如何产生的。 // App.jsconst App = () => { // ⛔️ Warning: Expected `onClick` listener to be a function // instead got a value of `string` type. return ( <div> <button onClick="console.log('Click')">Click</button> </div> );};export default App;当按钮的onClick属性的期望值是函数时,咱们为其传递了一个字符串,从而导致了谬误的产生。 传递函数为了解决该报错,请确保只为元素的onClick属性传递函数。 // App.jsconst App = () => { const handleClick = () => { console.log('button clicked'); }; return ( <div> <button onClick={handleClick}>Click</button> </div> );};export default App;咱们向元素的onClick属性传递了一个函数,顺利的解决了这个谬误。然而,留神到咱们在向onClick属性传递函数时并没有调用该函数。 咱们传递了函数的援用,而不是函数调用的后果。 如果传递了函数调用的后果,那么事件处理器将在页面加载时立刻被调用,这不是咱们想要的。传递参数你通常须要做的事件是向事件处理器传递一个参数。你能够通过应用一个内联箭头函数来做到这一点。 ...

August 17, 2022 · 1 min · jiezi

关于react.js:React报错之Type-JSXElement-is-not-assignable

注释从这开始~ 总览当咱们尝试从函数组件中返回元素组成的数组时,会产生"Type '() => JSX.Element[]' is not assignable to type FunctionComponent"谬误。为了解决该谬误,能够将元素数组包裹在React片段中。 这里有个示例用来展现谬误是如何产生的。 // App.tsximport React from 'react';// ⛔️ Type '() => JSX.Element[]' is not assignable to type 'FunctionComponent<{}>'.// Type 'Element[]' is missing the following properties// from type 'ReactElement<any, any>': type, props, key ts(2322)const App: React.FunctionComponent = () => { return ['Alice', 'Bob'].map(element => <div key={element}>{element}</div>);};export default App;这是齐全无效的React.js代码,因为咱们可能从React的函数组件中返回一个数组。然而,FunctionComponent接口的返回类型是ReactElement或null。 这也就意味着,咱们能够只返回一个React元素或者null值。 React片段为了解决该类型谬误,咱们必须将数组包裹在React片段(React fragment)中。 // App.tsximport React from 'react';const App: React.FunctionComponent = () => { return ( <> {['Alice', 'Bob'].map(element => ( <div key={element}>{element}</div> ))} </> );};export default App;当咱们须要对一个元素列表进行分组而不向DOM增加额定的节点时,就会用到片段。 ...

August 16, 2022 · 1 min · jiezi

关于react.js:React报错之JSX-element-type-does-not-have-any-construct

注释从这开始~ 总览当咱们试图将元素或react组件作为属性传递给另一个组件,然而属性的类型申明谬误时,会产生"JSX element type does not have any construct or call signatures"谬误。为了解决该谬误,能够应用React.ElementType类型。 这里有个例子来展现谬误是如何产生的。 // App.tsximport React from 'react';interface Props { comp: JSX.Element;}const Wrapper: React.FunctionComponent<Props> = props => { const {comp: Comp} = props; // ⛔️ JSX element type 'Comp' does not have any construct or call signatures.ts(2604) return ( <div> <Comp name="James" /> </div> );};const App: React.FunctionComponent = () => { const heading = ({name}: {name: string}) => <h2>Hello {name}</h2>; return ( <div> <Wrapper comp={heading} /> </div> );};export default App;咱们尝试将一个React组件作为属性传递给Wrapper组件,但咱们将该React组件的类型申明为JSX.Element。 ...

August 15, 2022 · 2 min · jiezi

关于react.js:React版Vue版都齐了不一样的开源后台管理系统坐等你来开箱

本我的项目次要基于Elux+Antd构建,蕴含React版本和Vue版本,旨在提供给大家一个简略根底、开箱即用的后盾管理系统通用模版,次要蕴含运行环境、脚手架、代码格调、根本Layout、状态治理、路由治理、增删改查逻辑、列表、表单等。 为放弃工程简略清新,不便二次开发,只提供根本版式和通用组件,不集成各种目迷五色的组件,须要的时候本人加进去就行了,Antd自身也自带很多组件。在线预览http://admin-react-antd.eluxj... Git仓库React版本 github: https://github.com/hiisea/elu...gitee: https://gitee.com/hiisea/elux...Vue版本 github: https://github.com/hiisea/elu...gitee: https://gitee.com/hiisea/elux...装置办法应用Git命令clone相应的库:git clone xxx也能够应用Elux提供的命令:npm create elux@latest 或 yarn create elux你看得见的UI 提供通用的Admin零碎Layout(包含注册、登录、遗记明码等)。 动静获取Menu菜单、轮询最新消息等。 反对第一次后退溢出,主动回到首页;再次后退则弹出提醒:您确定要来到本站?避免用户误操作。\提供<DocumentHead>组件,不便在SinglePage中保护document title、keyword、description等,该组件也可用于SSR,例如: <DocumentHead title={(id?'批改':'新增')+'用户'} /> 提供配置式查问表单, 还带TS类型验证哦,再也不放心写错字段名: const formItems: SearchFromItems<ListSearchFormData> = [ {name: 'name', label: '用户名', formItem: <Input placeholder="请输出关键字" />}, {name: 'nickname', label: '呢称', formItem: <Input placeholder="请输出呢称" />}, {name: 'status', label: '状态', formItem: <Select placeholder="请抉择用户状态" />}, {name: 'role', label: '角色', formItem: <Select placeholder="请抉择用户状态" />}, {name: 'email', label: 'Email', formItem: <Input placeholder="请输出Email" />},]; 提供开展与暗藏高级搜寻:开展高级 / 暗藏高级 提供跨页选取、从新搜寻后选取、review已选取:跨页选取 提供配置式批量操作等性能,如:批量操作 ...

August 15, 2022 · 4 min · jiezi

关于react.js:手撸Router还要啥Router框架让reactroutervuerouter躺一边凉快去

有没有发现,在大家应用React/Vue的时候,总离不开一个小尾巴,到哪都得带着他,那就是react-router/vue-router,而基于它们的第三方框架又呈现很多个性化约定和扩大,比方nuxtjs/nextjs/umijs都纷纷推出本人的路由计划。 有没有想过,其实你能够齐全解脱他们都解放?而且并不简单,上面听我来剖析剖析: State能够管制所有UI首先React/Vue都是基于MVVM架构,State能够决定Component的显示与否,而且很简略: // jsx{show? <SubUI /> : null}// vue<SubUI v-if="show" />也能够依据State来动态显示组件: <component :is="componentA"></component>管制UI的办法有很多,我就不例举了,总之State才是掌控UI的大脑中枢。 将URL映射为State路由的作用,无非就是依据Url来管制UI展现,那么你只须要将Url映射成为State,不就达到目标了? Url次要分2局部,pathname和query,有很多第三方库提供解析它们的办法,比方: pathname解析:path-to-regexp: const regexp = pathToRegexp("/:foo/:bar");regexp.exec("/test/route");具体用法大家看看官网文档就能够了,很简略... query解析:query其实很灵便,没有规定非得用什么格局,最简略的你间接用JSON.stringify将序列化后的字符串作为query也能够,如果你想遵循罕用的格局,你能够应用:query-string 或者 qs queryString.parse(location.search)好了,当初你能够拿到解析Url后的数据,而后把它们转换成你想要的State,寄存在全局Store中就能够了,比方你定义一个Url: /member/list/3?uname=lily//提取路由信息getRouteParams(): RouteParams { const query = queryString.parse(location.search); const [, curModule='', curView='', id=''] = pathToRegexp('/:curModule/:curView/:id') .exec(location.pathname) || []; if (curView === 'list') { //如果是列表,ID示意以后页码 return {...query, pageCurrent: id, curView} } else if(curView === 'detail') { return {...query, id, curView} }}而后在UI中拿到这几个State(可通过Redux或Vuex): const Component = ({curView}) => { return ( <> {curView === 'list' && <List />} {curView === 'detail' && <Detail />} </> );};发动路由跳转基于pushState和replaceState,封装一下就能够了: ...

August 15, 2022 · 1 min · jiezi

关于react.js:一种比cssscoped和cssmodule更优雅的避免css命名冲突小妙招

css_scoped 与 css_module咱们晓得,简略的class名称容易造成css命名反复,比方你定义一个class: <style>.main { float: left; }</style>如果他人刚好也定义了一个className:.main,你的float:left就会影响到它。 所以Vue中创造了css_scoped,其原理就是在class名称后加上一个data属性选择器: <style scoped>.main { float: left; } </style>//本义后变成<style>.main[data-v-49729759] { float: left }</style>css_scoped是Vue的专用计划,如果你应用React等其它UI框架,那么你能够应用更通用的css_module,其原理是为款式名加hash字符串后缀,从而保障class名全局惟一: <style module>.main { float: left; } </style>//本义后变成<style>.main_3FI3s6uz { float: left; } </style>相比于css_scoped,css_module计划更通用,不扭转其自身的权重,而且渲染性能要比前者好很多,所以更举荐大家应用css_module。 不足之处然而不论是css_scoped还是css_module,都绕不开2大毛病: 因为加上了随机字符,所以如果想在父组件中笼罩子组件中的款式变得麻烦,尽管css_scoped能够应用穿透,但这样容易引发别的问题。加上随机字符让class名称变得不优雅,也影响编译速度。css命名空间咱们来回顾一下,在css_scoped和css_module呈现之前,人们是如何防止css命名抵触的? 对,就是人为的定义一些css命名空间。 那个时候,对每个Component组件都会在其根节点上定义一个不反复的ID或者class作为其命名空间,而后其外部的其它class都会以此命名空间作为前置限定,比方: <div class="table-list"> <div class="hd"></div> <div class="bd"></div> <div class="ft"></div></div><style>.table-list { > .hd { color: red } > .bd { color: blue }} </style>这样一来,只有保障根节点的class不反复,其子节点的class就不会反复。 而对于一些全局款式,人们习惯加上一个g-作为命名空间,比方: <style>.g-hd { color: red} </style>这种依附人为约定的css命名空间,尽管比拟原始,但有其长处: 简略无效,按模块-组件名称的命名约定,基本上很容易保障其不反复。款式名更具语义,从任何一个dom登程,向上肯定能找到其组件根节点class名,基本上就能猜到其组件所在的业务模块、组件地位等。父组件很容易利用权重笼罩子组件的任何款式。css_namespace + css_module如果咱们把css_module和css_命名空间联合起来,组件的命名空间由css_module主动生成,那岂不是一种更优雅的解决css抵触的计划么? css_module中有2个特地的作用域限定符: :global 该限定符下的class名称将放弃原样,不会被css moudle转换,比方: :global { .test1 { color: blue; } .test2 { color: red; } }//编译后.test1 { color: blue; }.test2 { color: red; } :local 该限定符下的class名称,将会被css moudle转换,比方: ...

August 15, 2022 · 2 min · jiezi

关于react.js:React报错之Cannot-find-namespace-context

注释从这开始~ 总览在React中,为了解决"Cannot find namespace context"谬误,在你应用JSX的文件中应用.tsx扩展名,在你的tsconfig.json文件中把jsx设置为react-jsx,并确保为你的利用程序安装所有必要的@types包。 这里有个例子来展现谬误是如何产生的。 // App.tsimport React from 'react';interface UserCtx { first: string; last: string; age: number;}const AuthContext = React.createContext<UserCtx | null>(null);const authContext: UserCtx = { first: 'James', last: 'Doe', age: 30,};const App = () => { // ⛔️ Cannot find namespace 'AuthContext'.ts(2503) return ( <AuthContext.Provider value={authContext}> <h2>Your app here</h2> </AuthContext.Provider> );};export default App;上述代码片段的问题在于,文件的扩大名为.ts ,然而咱们在外面编写JSX代码。tsx这是不被容许的,因为为了能在TypeScript文件中应用JSX,咱们必须这样做: 以.tsx扩展名命名文件在tsconfig.json文件中开启jsx选项确保所有你编写JSX代码的文件都有.tsx扩展名。 // App.tsximport React from 'react';interface UserCtx { first: string; last: string; age: number;}const AuthContext = React.createContext<UserCtx | null>(null);const authContext: UserCtx = { first: 'James', last: 'Doe', age: 30,};const App = () => { return ( <AuthContext.Provider value={authContext}> <h2>Your app here</h2> </AuthContext.Provider> );};export default App;更新完文件的扩大名为.tsx后,如果问题仍未解决,请尝试重启你的IDE和开发服务器。 ...

August 14, 2022 · 2 min · jiezi

关于react.js:React-Hooks-学习

Hooks作用让函数组件领有class组件的个性(生命周期及状态)状态逻辑复用内置钩子useState(class 组件 state)useEffectcomponentDidMount(第二个参数为空)、componentDidUpdate(第二个参数不为空) 和 componentWillUnmount(第一个参数返回值)三个生命周期的组合 useLayoutEffect(应用办法同useEffect)区别:在浏览器执行绘制之前,useLayoutEffect 外部的更新打算将被同步刷新。阻塞渲染。 useLayoutEffect(应用办法同useEffect)区别:在浏览器执行绘制之前,useLayoutEffect 外部的更新打算将被同步刷新。阻塞渲染。 useReduceruseState 的代替计划,useState会笼罩原来的state,useReducer能够解决或合并旧state,生成新的state。它接管一个形如 (state, action) => newState 的 reducer,并返回以后的 state 以及与其配套的 dispatch 办法。 const [state, dispatch] = useReducer(reducer, initialArg, init);useCallbackuseCallback(fn, deps),返回一个 memoized 回调函数。useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。 useMemo把“创立”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项扭转时才从新计算 memoized 值。相似于vue computed计算属性。 Hook 应用规定只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。只能在 React 的函数组件中调用 Hook。不要在其余 JavaScript 函数中调用。

August 14, 2022 · 1 min · jiezi

关于react.js:React报错之Functions-are-not-valid-as-a-React-child

注释从这开始~ 总览产生"Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render."谬误,通常是因为以下两个起因: 从render中返回一个函数援用而不是一个组件。应用 react router 路由作为<Route path="/about" element={About} /> ,而不是<Route path="/about" element={<About />} /> 。 这里有个例子来展现谬误是如何产生的。 // App.js/** * ⛔️ Functions are not valid as a React child. * This may happen if you return a Component instead of <Component /> from render. * Or maybe you meant to call this function rather than return it. */const App = () => { const getButton = () => { return <button>Click</button>; }; // ️ returning function not JSX element from render return <div>{getButton}</div>;};export default App;下面代码片段的问题在于,咱们从render办法中返回getButton函数,而不是返回真正的JSX元素。 ...

August 13, 2022 · 2 min · jiezi

关于react.js:React报错之Encountered-two-children-with-the-same-key

注释从这开始~ 总览当咱们从map()办法返回的两个或两个以上的元素具备雷同的key属性时,会产生"Encountered two children with the same key"谬误。为了解决该谬误,为每个元素的key属性提供举世无双的值,或者应用索引参数。 这里有个例子来展现谬误是如何产生的。 // App.jsconst App = () => { // ️ name property is not a unique identifier const people = [ {id: 1, name: 'Alice'}, {id: 2, name: 'Bob'}, {id: 3, name: 'Alice'}, ]; /** * ⛔️ Encountered two children with the same key, `Alice`. * Keys should be unique so that components maintain their identity across updates. * Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version. */ return ( <div> {people.map(person => { return ( <div key={person.name}> <h2>{person.id}</h2> <h2>{person.name}</h2> </div> ); })} </div> );};export default App;上述代码片段的问题在于,咱们在每个对象上应用name属性作为key属性,然而name属性在整个对象中不是举世无双的。 ...

August 12, 2022 · 2 min · jiezi

关于react.js:NiceModal重新思考-React-中的弹窗使用方式

在开始进入正题之前,先看看一些与弹窗无关的乏味场景 。 一些乏味的实在场景案例一:全局弹窗 上图是掘金的登录弹窗,未登录状态下触发该弹窗展现的机会有很多,比方: 点击 Header 上的登录按钮文章列表页或详情页点赞以及评论文章发沸点、评论沸点以及点赞沸点...开发者往往会基于第三方组件库定义一个 <LoginModal />,而后将其挂载至 Root 组件下: function App() { const [visible, setVisible] = useState(false); const [otherLoginData, setOtherLoginData] = useState(); // other logic ... return ( <div className="app"> <Main /> <LoginModal visible={visible} onCancel={() => setVisible(false)} otherLoginData={otherLoginData} /> </div> );}这样会带来一些问题: <LoginModal /> 外部逻辑在组件渲染的时候就会执行,即便弹窗处于暗藏状态额定的复杂度。因为存在多个触发机会,须要将 setVisible 以及 setOtherLoginData 透传至 <Main /> 外部的多个子组件,你能够抉择通过 props 一层一层的传递进去(鬼晓得有多少层!),也能够引入工具进行状态共享,但不论怎样,这都不是一件容易的事;随着相似的弹窗越来越多,根组件会保护很多弹窗组件的状态...天知道为什么展现一个弹窗须要在多个文件里重复横跳。展现一个弹窗,为什么会变得如此简单? 以上案例来自 @ebay/nice-modal-react,稍作批改除了上述全局弹窗的场景,还有一种场景也很让人头疼。 案例二:存在分支以及依赖关系的弹窗 用户头疼,开发者也头疼弹窗 1 确认弹出弹窗 2,勾销则弹出弹窗 3,弹窗 2 以及 弹窗 3 也存在对应的分支逻辑,子孙满堂轻而易举,若依照惯例申明式弹窗组件的实现,十分恐怖! 不那么通用的解决方案解脱所谓的 React 哲学:数据驱动视图(view = f(data)),回归原始的 window.confirm 以及 window.alert,很多问题迎刃而解: ...

August 12, 2022 · 3 min · jiezi

关于react.js:浅谈我为什么不使用VueUse而选择造轮子

前言想想一名React开发开发Vue是什么体验。就在明天初含泪写多一个vue我的项目,不是转,是写多!选用的是vue3+vite开发。Composition API 让我得心应手。之前react开发选的是react16,ahooks是我接触最多的hooks库了,很贴合我的业务。在应用vue3的时候开发的时候选取了 vueuse 。 问题在前端开发中和申请打交道是最多的,大多数业务都是restful api架构,咱们拿到数据做解决,以后风行的框架装备着状态机制,在依赖变动时进行从新申请等。 vueuse 中的 useFetch 和 useAxios 是作为申请的 hook。useFetch性能比拟繁多,只有申请体的一些基本功能。useAxios 更多基于axios内置性能的封装,业务中的依赖刷新,防抖,节流,缓存等性能都没有的。这里就有小伙伴问了,那你在 useAxios上封装这些节流防抖性能就好了,先不说须要侵入式的批改这个钩子,它仅反对axios,万一我的项目变成request呢? ♂️ 解决ahooks 是基于 vueuse 的思维封装的 react 的 hooks,它含有更加丰盛的性能,能贴合咱们更多的业务,其中的 useRequest 是满足我的需要的,但苦于没有vue版本,于是我感觉本人开发一版基于vue3个性的useRequest 。它具备了ahooks的所有性能: 主动申请/手动申请轮询防抖节流屏幕聚焦从新申请谬误重试loading delaySWR(stale-while-revalidate)缓存插件式const {  loading: Ref<boolean>,  data?: Ref<TData>,  error?: Ref<Error>,  params: Ref<TParams || []>,  run: (...params: TParams) => void,  runAsync: (...params: TParams) => Promise<TData>,  refresh: () => void,  refreshAsync: () => Promise<TData>,  mutate: (data?: TData | ((oldData?: TData) => (TData | undefined))) => void,  cancel: () => void,} = useRequest<TData, TParams>(  service: (...args: TParams) => Promise<TData>, {    manual?: boolean,    defaultParams?: TParams,    onBefore?: (params: TParams) => void,    onSuccess?: (data: TData, params: TParams) => void,    onError?: (e: Error, params: TParams) => void,    onFinally?: (params: TParams, data?: TData, e?: Error) => void,    ...高级性能,更多请见文档 });这个useRequest 申请体容许传入任意promise对象,所以它并不限度是axios还是request,并且性能都是统一的。如果想应用申请库的一些特定性能,咱们能够封装那些特定性能成为useRequest的插件,能够管制在它的生命周期中调用。所以它既体现出包容性又体现出对于单个个体非凡性能的接收。 ...

August 12, 2022 · 2 min · jiezi

关于react.js:React报错之Cannot-assign-to-current

注释从这开始~ 总览当咱们用一个null值初始化一个ref,但在其类型中不包含null时,就会产生"Cannot assign to 'current' because it is a read-only property"谬误。为了解决该谬误,请在ref的类型中蕴含null。比如说,const ref = useRef<string | null>(null) 。 这里有个例子来展现谬误是如何产生的。 // App.tsximport {useEffect, useRef} from 'react';const App = () => { const ref = useRef<string>(null); useEffect(() => { // ⛔️ Error: Cannot assign to 'current' because it is a read-only property.ts(2540) ref.current = 'hello'; }, []); return ( <div> <h2>hello world</h2> </div> );};export default App;下面例子的问题在于,当咱们将null作为初始值传递到useRef钩子中时,并且咱们传递给钩子的泛型中没有包含null类型,咱们创立了一个不可变的ref对象。 正确的泛型为了解决该谬误,咱们必须在传递给钩子的泛型中包含null类型。 // App.tsximport {useEffect, useRef} from 'react';const App = () => { // ️ include null in the ref's type const ref = useRef<string | null>(null); useEffect(() => { ref.current = 'hello'; }, []); return ( <div> <h2>hello world</h2> </div> );};export default App;在ref的类型中,咱们应用联结类型来包含null类型,这使它成为可变ref对象。 ...

August 11, 2022 · 1 min · jiezi

关于react.js:React报错之The-tag-is-unrecognized-in-this-browser

注释从这开始~ 总览当咱们应用一个在浏览器中不存在的标签或以小写字母结尾的组件名称时,会产生"The tag is unrecognized in this browser"React正告。为了解决该问题,只应用无效的标签名称,并将你的组件的第一个字母大写。 这里有个例子来展现谬误是如何产生的。 // App.jsconst App = () => { // ⛔️ Warning: The tag <p1> is unrecognized in this browser. // If you meant to render a React component, start its name with an uppercase letter. return ( <div> <div> <p1>Hello world</p1> </div> </div> );};export default App;上述代码的问题在于,咱们应用了p1标签,但该标签并不存在于浏览器中。 确保标签存在咱们必须确保只应用受反对的标签。你能够在这里查看所有Web反对的标签。你能够通过应用CTRL + F来查看一个特定的标签是否存在,并查找该标签,例如<li>。 为了解决上述示例的谬误,咱们必须应用一个存在的标签名称。比如说,h1标签或者p标签。 const App = () => { return ( <div> <div> <h1>Hello world</h1> </div> </div> );};export default App;小写字母结尾导致"The tag is unrecognized in this browser"正告的另一个起因是,当咱们以小写字母结尾一个组件名称时。 ...

August 10, 2022 · 1 min · jiezi

关于react.js:React报错之Style-prop-value-must-be-an-object

注释从这开始~ 总览在React中,当咱们为元素的style 属性传递字符串时,会产生"Style prop value must be an object"正告。为了解决该正告,应用从属性到值的映射。比如说,style={{paddingLeft: '15px'}} 。 这里有个例子来展现谬误是如何产生的。 // App.jsconst App = () => { // ⛔️ Style prop value must be an object eslint(react/style-prop-object) return ( <div> <h1 style="margin-left: 4rem">Hello world</h1> </div> );};export default App;映射上述代码的问题在于,咱们为h1元素的style属性传递了字符串。相同,style属性应该传递从属性到值的映射。 const App = () => { return ( <div> <h1 style={{ marginLeft: '4rem', fontSize: '20px', padding: '20px', backgroundColor: 'salmon', color: 'white', }} > Hello world </h1> </div> );};export default App;须要留神的是,这里咱们应用了2对大括号。外侧的大括号是对一个表达式的求值,内侧的大括号是蕴含属性名称和值的对象。你还能够应用逻辑来计算特定的值。 ...

August 9, 2022 · 1 min · jiezi

关于react.js:React报错之useNavigate-may-be-used-only-in-context-of-Router

注释从这开始~ 总览当咱们尝试在react router的Router上下文内部应用useNavigate 钩子时,会产生"useNavigate() may be used only in the context of a Router component"正告。为了解决该问题,只在Router上下文中应用useNavigate 钩子。 上面是一个在index.js文件中将React利用包裹到Router中的例子。 // index.jsimport {createRoot} from 'react-dom/client';import App from './App';import {BrowserRouter as Router} from 'react-router-dom';const rootElement = document.getElementById('root');const root = createRoot(rootElement);// ️ wrap App in Routerroot.render( <Router> <App /> </Router>);useNavigate当初,你能够在App.js文件中应用useNavigate钩子。 // App.jsimport React from 'react';import { useNavigate,} from 'react-router-dom';export default function App() { const navigate = useNavigate(); const handleClick = () => { // ️ navigate programmatically navigate('/about'); }; return ( <div> <button onClick={handleClick}>Navigate to About</button> </div> );}会产生谬误是因为useNavigate钩子应用了Router组件提供的上下文,所以它必须嵌套在Router外面。 ...

August 8, 2022 · 1 min · jiezi

关于react.js:React报错之react-component-changing-uncontrolled-input

注释从这开始~ 总览当input的值被初始化为undefined,但起初又变更为一个不同的值时,会产生"A component is changing an uncontrolled input to be controlled"正告。为了解决该问题,将input的值初始化为空字符串。比如说,value={message || ''} 。 这里有个例子来展现谬误是如何产生的。 import {useState} from 'react';const App = () => { // ️ didn't provide an initial value for message const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); }; return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> </div> );};export default App;下面代码的问题在于,message变量被初始化为undefined,因为咱们没有在useState钩子中为其传递初始值。 备用值解决该谬误的一种形式是,如果input的值为undefined,那么就提供一个备用值。 import {useState} from 'react';const App = () => { const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); }; // ️ value={message || ''} return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message || ''} /> </div> );};export default App;咱们应用逻辑与(||)操作符,如果操作符左侧的为假值(比如说undefined),则返回其右侧的值。 ...

August 7, 2022 · 1 min · jiezi

关于react.js:React报错之value-prop-on-input-should-not-be-null

注释从这开始~ 总览当咱们把一个input的初始值设置为null或者笼罩初始值设置为null时,会产生"valueprop on input should not be null"正告。比如说,初始值来自于空的API响应。能够应用一个回退值来解决这个问题。 这里有个例子来展现谬误是如何产生的。 export default function App() { // ⛔️ Warning: `value` prop on `input` should not be null. // Consider using an empty string to clear the component or `undefined` for uncontrolled components. return ( <div> <input value={null} /> </div> );}上述代码的问题在于,咱们为input表单的value属性设置为null,这是不被容许的。 你也可能从近程API获取你的input表单的值,并将其设置为null。回退值为了解决该问题,咱们能够通过提供回退值,来确保永远不会为input表单的value属性设置null。 import {useState} from 'react';const App = () => { // ️ pass empty string as initial value const [message, setMessage] = useState(''); const handleChange = event => { setMessage(event.target.value); }; // ✅ use fallback, e.g. // value={message || ''} return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message || ''} /> </div> );};export default App;咱们把state变量的值初始化为一个空字符串,而不是null。这样就能够解脱正告,除非在你代码的其余中央将state变量设置为null。 ...

August 6, 2022 · 1 min · jiezi

关于react.js:React报错之No-duplicate-props-allowed

注释从这开始~ 总览当咱们为雷同的组件传递雷同的属性屡次时,就会导致"No duplicate props allowed"正告。为了解决该正告,请确保只传递一次该属性。比如说,如果传递屡次className属性,将它们连接成一个空格分隔的字符串。 上面的示例用来展现如何导致正告的。 const App = () => { // ⛔️ JSX elements cannot have multiple attributes with the same name.ts(17001) // No duplicate props allowed eslintreact/jsx-no-duplicate-props return ( <div> <Button text="Click" text="Submit" /> </div> );};function Button({text}) { return <button onClick={() => console.log('button clicked')}>{text}</button>;}export default App;代码片段中的问题在于,咱们为Button组件传递了两次text属性。这是不被容许的,因为第二个text属性会笼罩第一个。 请确保每个属性只传递给同一个组件一次。 const App = () => { // ️ only pass text prop once return ( <div> <Button text="Submit" /> </div> );};function Button({text}) { return <button onClick={() => console.log('button clicked')}>{text}</button>;}export default App;className如果你在试图传递多个className属性时失去了谬误,你必须将它们串联成一个字符串,并且只传递一次属性。 ...

August 5, 2022 · 1 min · jiezi

关于react.js:React-Each-child-in-a-list-should-have-a-unique-key-prop-解决

react + ant design应用table时,呈现了报错,错误信息如下Each child in a list should have a unique “key“ prop.呈现这个问题,table的每一行须要一个"key"。 如果table的 dataSource[i].key 这个属性不存在能够在 Table上增加一个rowKeyrowKey能够是一个字符串,指定dataSource[i]上的一个属性也能够是一个函数,返回dataSource[i]上的一个key 举个例子: 代码起源是ant design官网的table (ts版本)https://ant.design/components..."简略的表格,最初一列是各种操作。" // ↓ 去掉了官网代码中的data[i].key const data: DataType[] = [ { name: 'John Brown', age: 32, address: 'New York No. 1 Lake Park', tags: ['nice', 'developer'], }, { name: 'Jim Green', age: 42, address: 'London No. 1 Lake Park', tags: ['loser'], }, { name: 'Joe Black', age: 32, address: 'Sidney No. 1 Lake Park', tags: ['cool', 'teacher'], },];const App: React.FC = () => <Table columns={columns} dataSource={data} />;// ↑ 下面的写法会报错 Each child in a list should have a unique “key“ prop. ...

August 5, 2022 · 1 min · jiezi

关于react.js:React报错之Objects-are-not-valid-as-a-React-child

注释从这开始~ 总览当咱们尝试在JSX代码中,间接渲染对象或者数组时,会产生"Objects are not valid as a React child"谬误。为了解决该谬误,在JSX代码中,应用map()办法来渲染数组或者拜访对象的属性。 上面是谬误如何产生的示例。 export default function App() { const employees = [ {id: 1, name: 'Alice', country: 'Austria'}, {id: 2, name: 'Bob', country: 'Belgium'}, {id: 3, name: 'Carl', country: 'Canada'}, ]; const obj = { id: 4, name: 'Dean', country: 'Denmark', }; // ⛔️ Uncaught Error: Objects are not valid as a React child (found: object with keys {id, name, country}). // If you meant to render a collection of children, use an array instead. return ( <div> {employees} {obj} </div> );}map上述代码片段的问题在于,在JSX代码中咱们尝试间接渲染数组或者对象。 ...

August 4, 2022 · 2 min · jiezi

关于react.js:React-Fiber架构原理剖析

一、概述在 React 16 之前,VirtualDOM 的更新采纳的是Stack架构实现的,也就是循环递归形式。不过,这种比照形式有显著的缺点,就是一旦工作开始进行就无奈中断,如果遇到利用中组件数量比拟宏大,那么VirtualDOM 的层级就会比拟深,带来的后果就是主线程被长期占用,进而阻塞渲染、造成卡顿景象。 为了避免出现卡顿等问题,咱们必须保障在执行更新操作时计算时不能超过16ms,如果超过16ms,就须要先暂停,让给浏览器进行渲染,后续再继续执行更新计算。而Fiber架构就是为了反对“可中断渲染”而创立的。 在React中,Fiber应用了一种新的数据结构fiber tree,它能够把虚构dom tree转换成一个链表,而后再执行遍历操作,而链表在执行遍历操作时是反对断点重启的,示意图如下。 二、Fiber架构2.1 执行单元官网介绍中,Fiber 被了解为是一种数据结构,然而咱们也能够将它了解为是一个执行单元。 Fiber 能够了解为一个执行单元,每次执行完一个执行单元,React Fiber就会查看还剩多少工夫,如果没有工夫则将控制权让进来,而后由浏览器执行渲染操作。React Fiber 与浏览器的交互流程如下图。 能够看到,React 首先向浏览器申请调度,浏览器在执行完一帧后如果还有闲暇工夫,会去判断是否存在待执行工作,不存在就间接将控制权交给浏览器;如果存在就会执行对应的工作,执行完一个新的工作单元之后会持续判断是否还有工夫,有工夫且有待执行工作则会继续执行下一个工作,否则将控制权交给浏览器执行渲染,这个流程是循环进行的。 所以,咱们能够将Fiber 了解为一个执行单元,并且这个执行单元必须是一次实现的,不能呈现暂停。并且,这个小的执行单元在执行完后计算之后,能够移交控制权给浏览器去响应用户,从而晋升了渲染的效率。 2.2 数据结构在官网的文档中,Fiber 被解释为是一种数据结构,即链表构造。在链表构造中,每个 Virtual DOM 都能够示意为一个 fiber,如下图所示。 通常,一个 fiber包含了 child(第一个子节点)、sibling(兄弟节点)、return(父节点)等属性,React Fiber 机制的实现,就是依赖于下面的数据结构。 2.3 Fiber链表构造通过介绍,咱们晓得Fiber应用的是链表构造,精确的说是单链表树结构,详见ReactFiber.js源码。为了放便了解 Fiber 的遍历过程,上面咱们就看下Fiber链表构造。 在下面的例子中,每一个单元都蕴含了payload(数据)和nextUpdate(指向下一个单元的指针)两个元素,定义构造如下: class Update { constructor(payload, nextUpdate) { this.payload = payload //payload 数据 this.nextUpdate = nextUpdate //指向下一个节点的指针 }}接下来定义一个队列,把每个单元串联起来。为此,咱们须要定义两个指针:头指针firstUpdate和尾指针lastUpdate,作用是指向第一个单元和最初一个单元,而后再退出baseState属性存储React中的state状态。 class UpdateQueue { constructor() { this.baseState = null // state this.firstUpdate = null // 第一个更新 this.lastUpdate = null // 最初一个更新 }}接下来,再定义两个办法:用于插入节点单元的enqueueUpdate()和用于更新队列的forceUpdate()。并且,插入节点单元时须要思考是否曾经存在节点,如果不存在间接将firstUpdate、lastUpdate指向此节点即可。更新队列是遍历这个链表,依据payload中的内容去更新state的值 ...

August 4, 2022 · 5 min · jiezi

关于react.js:React报错之无法在未挂载的组件上执行React状态更新

注释从这开始~ 总览为了解决"Warning: Can't perform a React state update on an unmounted component" ,能够在你的useEffect钩子中申明一个isMounted布尔值,用来跟踪组件是否被装置。一个组件的状态只有在该组件被挂载时才会被更新。 import {useState, useEffect} from 'react';const App = () => { const [state, setState] = useState(''); useEffect(() => { // ️ set isMounted to true let isMounted = true; async function fetchData() { const result = await Promise.resolve(['hello', 'world']); // ️ only update state if component is mounted if (isMounted) { setState(result); } } fetchData(); return () => { // ️ when component unmounts, set isMounted to false isMounted = false; }; }, []); return ( <div> <h2>State: {JSON.stringify(state)}</h2> </div> );};export default App;当咱们试图更新一个未挂载的组件的状态时,会呈现"无奈在未挂载的组件上执行React状态更新"的正告。isMounted解脱该正告的含糊其辞的形式是,在useEffect钩子中应用isMounted布尔值来跟踪组件是否被挂载。 ...

August 3, 2022 · 2 min · jiezi

关于react.js:React报错之map-is-not-a-function

注释从这开始~ 总览当咱们对一个不是数组的值调用map()办法时,就会产生"TypeError: map is not a function"谬误。为了解决该谬误,请将你调用map()办法的值记录在console.log上,并确保只对无效的数组调用map。 这里有个示例来展现谬误是如何产生的。 const App = () => { const obj = {}; // ⛔️ Uncaught TypeError: map is not a function return ( <div> {obj.map(element => { return <h2>{element}</h2>; })} </div> );};export default App;咱们在一个对象上调用Array.map()办法,失去了谬误反馈。 为了解决该谬误,请console.log你调用map办法的值,确保它是一个无效的数组。 export default function App() { const arr = ['one', 'two', 'three']; return ( <div> {arr.map((element, index) => { return ( <div key={index}> <h2>{element}</h2> </div> ); })} </div> );}Array.isArray你能够通过应用Array.isArray办法,来有条件地查看值是否为数组。 ...

August 2, 2022 · 1 min · jiezi

关于react.js:React高频面试题合集二

什么是虚构DOM?虚构 DOM (VDOM)是实在 DOM 在内存中的示意。UI 的示意模式保留在内存中,并与理论的 DOM 同步。这是一个产生在渲染函数被调用和元素在屏幕上显示之间的步骤,整个过程被称为和谐。 React中的状态是什么?它是如何应用的状态是 React 组件的外围,是数据的起源,必须尽可能简略。基本上状态是确定组件出现和行为的对象。与props 不同,它们是可变的,并创立动静和交互式组件。能够通过 this.state() 拜访它们。 虚构 DOM 的引入与间接操作原生 DOM 相比,哪一个效率更高,为什么虚构DOM绝对原生的DOM不肯定是效率更高,如果只批改一个按钮的文案,那么虚构 DOM 的操作无论如何都不可能比实在的 DOM 操作更快。在首次渲染大量DOM时,因为多了一层虚构DOM的计算,虚构DOM也会比innerHTML插入慢。它能保障性能上限,在实在DOM操作的时候进行针对性的优化时,还是更快的。所以要依据具体的场景进行探讨。 在整个 DOM 操作的演化过程中,其实主要矛盾并不在于性能,而在于开发者写得爽不爽,在于研发体验/研发效率。虚构 DOM 不是别的,正是前端开发们为了谋求更好的研发体验和研发效率而发明进去的高阶产物。虚构 DOM 并不一定会带来更好的性能,React 官网也素来没有把虚构 DOM 作为性能层面的卖点对外输入过。**虚构 DOM 的优越之处在于,它可能在提供更爽、更高效的研发模式(也就是函数式的 UI 编程形式)的同时,依然放弃一个还不错的性能。 为什么 useState 要应用数组而不是对象useState 的用法: const [count, setCount] = useState(0)复制代码能够看到 useState 返回的是一个数组,那么为什么是返回数组而不是返回对象呢? 这里用到了解构赋值,所以先来看一下ES6 的解构赋值: 数组的解构赋值const foo = [1, 2, 3];const [one, two, three] = foo;console.log(one); // 1console.log(two); // 2console.log(three); // 3复制代码对象的解构赋值const user = { id: 888, name: "xiaoxin"};const { id, name } = user;console.log(id); // 888console.log(name); // "xiaoxin"复制代码看完这两个例子,答案应该就进去了: ...

August 2, 2022 · 5 min · jiezi

关于react.js:react高频面试题总结一

React Hook 的应用限度有哪些?React Hooks 的限度次要有两条: 不要在循环、条件或嵌套函数中调用 Hook;在 React 的函数组件中调用 Hook。那为什么会有这样的限度呢?Hooks 的设计初衷是为了改良 React 组件的开发模式。在旧有的开发模式下遇到了三个问题。 组件之间难以复用状态逻辑。过来常见的解决方案是高阶组件、render props 及状态治理框架。简单的组件变得难以了解。生命周期函数与业务逻辑耦合太深,导致关联局部难以拆分。人和机器都很容易混同类。常见的有 this 的问题,但在 React 团队中还有类难以优化的问题,心愿在编译优化层面做出一些改良。这三个问题在肯定水平上妨碍了 React 的后续倒退,所以为了解决这三个问题,Hooks 基于函数组件开始设计。然而第三个问题决定了 Hooks 只反对函数组件。 那为什么不要在循环、条件或嵌套函数中调用 Hook 呢?因为 Hooks 的设计是基于数组实现。在调用时按程序退出数组中,如果应用循环、条件或嵌套函数很有可能导致数组取值错位,执行谬误的 Hook。当然,本质上 React 的源码里不是数组,是链表。 这些限度会在编码上造成肯定水平的心智累赘,老手可能会写错,为了防止这样的状况,能够引入 ESLint 的 Hooks 查看插件进行预防。 react16版本的reconciliation阶段和commit阶段是什么reconciliation阶段蕴含的次要工作是对current tree 和 new tree 做diff计算,找出变动局部。进行遍历、比照等是能够中断,歇一会儿接着再来。commit阶段是对上一阶段获取到的变动局部利用到实在的DOM树中,是一系列的DOM操作。不仅要保护更简单的DOM状态,而且中断后再持续,会对用户体验造成影响。在广泛的利用场景下,此阶段的耗时比diff计算等耗时绝对短。state 是怎么注入到组件的,从 reducer 到组件经验了什么样的过程通过connect和mapStateToProps将state注入到组件中: import { connect } from 'react-redux'import { setVisibilityFilter } from '@/reducers/Todo/actions'import Link from '@/containers/Todo/components/Link'const mapStateToProps = (state, ownProps) => ({ active: ownProps.filter === state.visibilityFilter})const mapDispatchToProps = (dispatch, ownProps) => ({ setFilter: () => { dispatch(setVisibilityFilter(ownProps.filter)) }})export default connect( mapStateToProps, mapDispatchToProps)(Link)复制代码下面代码中,active就是注入到Link组件中的状态。 mapStateToProps(state,ownProps)中带有两个参数,含意是∶ ...

August 2, 2022 · 4 min · jiezi

关于react.js:react常见面试题

组件之间传值父组件给子组件传值 在父组件中用标签属性的=模式传值 在子组件中应用props来获取值 子组件给父组件传值 在组件中传递一个函数 在子组件中用props来获取传递的函数,而后执行该函数 在执行函数的时候把须要传递的值当成函数的实参进行传递 兄弟组件之间传值 利用父组件 先把数据通过 【子组件】===》【父组件】 而后在数据通过 【父组件】===〉【子组件】 音讯订阅 应用PubSubJs插件 为何React事件要本人绑定this在 React源码中,当具体到某一事件处理函数将要调用时,将调用 invokeGuardedCallback办法。 function invokeGuardedCallback(name, func, a) { try { func(a); } catch (x) { if (caughtError === null) { caughtError = x; } }}事件处理函数是间接调用的,并没有指定调用的组件,所以不进行手动绑定的状况下间接获取到的 this是不精确的,所以咱们须要手动将以后组件绑定到 this上 应用箭头函数(arrow functions)的长处是什么作用域平安:在箭头函数之前,每一个新创建的函数都有定义本身的 this 值(在构造函数中是新对象;在严格模式下,函数调用中的 this 是未定义的;如果函数被称为“对象办法”,则为根底对象等),但箭头函数不会,它会应用关闭执行上下文的 this 值。简略:箭头函数易于浏览和书写清晰:当一切都是一个箭头函数,任何惯例函数都能够立刻用于定义作用域。开发者总是能够查找 next-higher 函数语句,以查看 this 的值解释 React 中 render() 的目标。每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的示意。如果须要渲染多个 HTML 元素,则必须将它们组合在一个关闭标记内,例如 <form>、<group>、<div> 等。此函数必须放弃污浊,即必须每次调用时都返回雷同的后果。 指出(组件)生命周期办法的不同componentWillMount -- 多用于根组件中的应用程序配置componentDidMount -- 在这能够实现所有没有 DOM 就不能做的所有配置,并开始获取所有你须要的数据;如果须要设置事件监听,也能够在这实现componentWillReceiveProps -- 这个周期函数作用于特定的 prop 扭转导致的 state 转换shouldComponentUpdate -- 如果你放心组件适度渲染,shouldComponentUpdate 是一个改善性能的中央,因为如果组件接管了新的 prop, 它能够阻止(组件)从新渲染。shouldComponentUpdate 应该返回一个布尔值来决定组件是否要从新渲染componentWillUpdate -- 很少应用。它能够用于代替组件的 componentWillReceiveProps 和 shouldComponentUpdate(但不能拜访之前的 props)componentDidUpdate -- 罕用于更新 DOM,响应 prop 或 state 的扭转componentWillUnmount -- 在这你能够勾销网络申请,或者移除所有与组件相干的事件监听器React中constructor和getInitialState的区别?两者都是用来初始化state的。前者是ES6中的语法,后者是ES5中的语法,新版本的React中曾经废除了该办法。 ...

August 2, 2022 · 4 min · jiezi

关于react.js:React报错之ref返回undefined或null

注释从这开始~ 总览当咱们试图在其对应的DOM元素被渲染之前拜访其current属性时,React的ref通常会返回undefined或者null。为了解决该问题,能够在useEffect钩子中拜访ref,或者当事件触发时再拜访ref。 import {useRef, useEffect} from 'react';export default function App() { const ref = useRef(); console.log(ref.current); // ️ undefined here useEffect(() => { const el2 = ref.current; console.log(el2); // ️ element here }, []); return ( <div> <div ref={ref}> <h2>Hello</h2> </div> </div> );}useEffectuseRef()钩子能够传递一个初始值作为参数。该钩子返回一个可变的ref对象,ref对象上的current属性被初始化为传递的参数。 咱们没有为useRef传递初始值,因而其current属性设置为undefined。如果咱们将null传递给钩子,如果立刻拜访其current属性,将会失去null。 须要留神的是,咱们必须拜访ref对象上的current属性,以此来拜访设置了ref属性的div元素。当咱们为元素传递ref属性时,比如说,<div ref={myRef} /> ,React将ref对象的.current属性设置为相应的DOM节点。 咱们应用useEffect钩子,是因为咱们想要确保ref曾经设置在元素上,并且元素曾经渲染到DOM上。 如果咱们尝试在组件中间接拜访ref上的current属性,咱们会失去undefined,是因为 ref 还没有被设置,而且 div 元素还没有被渲染。 事件你也能够在事件处理函数中拜访ref的current属性。 import {useRef, useEffect} from 'react';export default function App() { const ref = useRef(); console.log(ref.current); // ️ undefined here useEffect(() => { const el2 = ref.current; console.log(el2); // ️ element here }, []); const handleClick = () => { console.log(ref.current); // ️ element here }; return ( <div> <div ref={ref}> <h2>Hello</h2> </div> <button onClick={handleClick}>Click</button> </div> );}当用户点击按钮的时候,ref曾经被设置好了,相应的元素曾经被渲染到DOM中,所以咱们可能拜访它。 ...

August 1, 2022 · 1 min · jiezi

关于react.js:React报错之Property-X-does-not-exist-on-type-HTMLElement

注释从这开始~ 总览在React中,当咱们试图拜访类型为HTMLElement 的元素上不存在的属性时,就会产生Property 'X' does not exist on type 'HTMLElement'谬误。为了解决该谬误,在拜访属性之前,应用类型断言来正确地类型申明元素。 这里有三个例子来展现谬误是如何产生的。 // App.tsximport {useEffect} from 'react';export default function App() { useEffect(() => { const input = document.getElementById('first_name'); // ⛔️ Property 'value' does not exist on type 'HTMLElement'.ts(2339) console.log(input?.value); // ----------------------------------------------------------------- const link = document.getElementById('link'); // ⛔️ Property 'href' does not exist on type 'HTMLElement'.ts(2339) console.log(link?.href); // ----------------------------------------------------------------- const button = document.getElementById('btn'); if (button != null) { // ⛔️ Property 'disabled' does not exist on type 'HTMLElement'.ts(2339) button.disabled = true; } }, []); return ( <div> <input id="first_name" type="text" name="first_name" defaultValue="Initial Value" /> <a id="link" href="<https://google.com>" target="_blank" rel="noreferrer"> Open Google </a> <button id="btn">Submit</button> </div> );}产生谬误的起因是,document.getElementById办法的返回类型是HTMLElement | null,然而咱们试图拜访的属性不存在于HTMLElement 类型。 ...

July 31, 2022 · 2 min · jiezi

关于react.js:React报错之Cannot-find-name

注释从这开始~ .tsx扩展名为了在React TypeScript中解决Cannot find name报错,咱们须要在应用JSX文件时应用.tsx扩展名,在你的tsconfig.json文件中把jsx设置为react-jsx ,并确保为你的利用程序安装所有必要的@types包。 上面是在名为App.ts的文件中产生谬误的示例。 export default function App() { // ⛔️ Cannot find name 'div'.ts(2304) return ( <div> <input type="text" id="message" value="Initial value" /> {/* Cannot find name 'button'.ts(2304) */} <button>Click</button> </div> );}上述示例代码的问题在于,咱们的文件扩大名为.ts,然而咱们在外面却写的JSX代码。这是不被容许的,因而为了在TS文件中应用JSX,咱们必须: 将文件命名为.tsx扩展名;在tsconfig.json中启用jsx选项。确保编写JSX代码的所有文件领有.tsx扩展名。 // App.tsxexport default function App() { return ( <div> <input type="text" id="message" value="Initial value" /> <button>Click</button> </div> );}如果在更新文件扩大名为.tsx后,问题仍然没有解决,请尝试重启IDE和开发服务器。 tsconfig.json配置文件关上tsconfig.json文件,确保jsx选项设置为react-jsx。 { "compilerOptions": { "jsx": "react-jsx", // ️ make sure you have this "target": "es6", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true }, "include": ["src/**/*"]}当jsx选项设置为react-jsx ,它会导致编译器应用JSX,将.js文件改为_jsx调用。 ...

July 30, 2022 · 1 min · jiezi

关于react.js:React报错之Object-is-possibly-null

注释从这开始~ 类型守卫应用类型守卫来解决React中useRef钩子“Object is possibly null”的谬误。比如说,if (inputRef.current) {} 。一旦null被排除在ref的类型之外,咱们就可能拜访ref上的属性。 上面是一个谬误如何产生的示例。 import {useEffect, useRef} from 'react';export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // ⛔️ Object is possibly 'null'.ts(2531) inputRef.current.focus(); }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> <button>Click</button> </div> );}代码片段中的问题是,TypeScript不能确保咱们将一个元素或者一个值赋值给ref,所以它的current属性可能为null。 为了解决这个谬误,在拜访ref类型上的属性之前,咱们必须应用类型守卫来从其类型中排除null。 import {useEffect, useRef} from 'react';export default function App() { const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { // ️ ref could be null here if (inputRef.current != null) { // ️ TypeScript knows that ref is not null here inputRef.current.focus(); } }, []); return ( <div> <input ref={inputRef} type="text" id="message" /> <button>Click</button> </div> );}咱们应用简略的if语句作为类型守卫,来确保ref上的current属性不存储null。当程序进入到if代码块中,TypeScript就会晓得ref对象上的current属性就不会存储null。 ...

July 29, 2022 · 1 min · jiezi

关于react.js:Hooks时代如何写出高质量的react和vue组件

0、概述一个组件外部的所有代码——无论vue还是react——都能够形象成以下几个局部: 组件视图,组件中用来形容视觉效果的局部,如css和html、react的jsx或者vue的template代码组件相干逻辑,如组件生命周期,按钮交互,事件等业务相干逻辑,如登录注册,获取用户信息,获取商品列表等与组件无关的业务形象 独自拆分这三块并不难,难的是一个组件可能写得特地简单,外面可能蕴含了多个视图,每个视图相互之间又有交互;同时又可能蕴含多个业务逻辑,多个业务的函数和变量横七竖八地随便搁置,导致后续保护的时候要在代码之间重复横跳。要写出高质量的组件,能够思考以下几个问题:1.组件什么时候拆?怎么拆?一个常见的误区是,只有须要复用的时候才去拆分组件,这种认识显然过于全面了。你能够思考一下,本人是如何形象一个函数的,你只会在代码须要复用的时候才抽出一个函数吗?显然不是。因为函数不仅有代码复用的性能,还具备肯定的形容性质以及代码封闭性。这种个性使得咱们看到一个函数的时候,不用关注代码细节,就能大略晓得这部分代码是干啥的。咱们还能够再用函数将一部分函数组合起来,造成更高层级的形象。按国内风行的说法,高层级的形象被称为粗粒度,低层级的形象被称为细粒度,不同粗细粒度的形象能够称它们为不同的形象层级。并且一个现实的函数外部,个别只会蕴含同一形象层级的代码。组件的拆分也能够遵循同样的情理。咱们能够依照以后的构造或者性能、业务,将组件拆分为性能清晰且繁多、与内部耦合水平低的组件(即所谓高内聚,低耦合)。如果一个组件外面干了太多事,或者依赖的内部状态太多,那么就不是一个容易保护的组件了。 然而,为了放弃组件性能繁多,咱们是不是要将组件拆分得特地细才能够呢?事实并非如此。因为下面说过,形象是有粗细粒度之分的,兴许一个组件从较细的粒度来讲性能并不繁多,然而从较粗的粒度来说,可能他们的性能就是繁多的了。例如登录和注册是两个不同的性能,然而你从更高层级的形象来看,它们都属于用户模块的一部分。所以是否要拆分组件,最要害还是得看复杂度。如果一个页面特地简略,那么不进行拆分也是能够,有时候拆分得过于细可能反而不利于保护。如何判断一个组件是否简单?恐怕这里不能给出一个精确的答案,毕竟代码的实现形式千奇百怪,很难有一个机械的规范评判。然而咱们无妨站在第三方角度看看本人的代码,如果你是一个工作一年的程序员,是否能比拟容易地看懂这里的代码?如果不能就要思考进行拆分了。如果你非要一个机械的判断规范,我倡议是代码管制在200行内。总结一下,拆分组件的时候能够参考上面几个准则: 拆分的组件要放弃性能繁多。即组件外部代码的代码都只跟这个性能相干;组件要放弃较低的耦合度,不要与组件内部产生过多的交互。如组件外部不要依赖过多的内部变量,父子组件的交互不要搞得太简单等等。用组件名精确形容这个组件的性能。就像函数那样,能够让人不必关怀组件细节,就大略晓得这个组件是干嘛的。如果起名比拟艰难,思考下是不是这个组件的性能并不繁多。 2.如何组织拆分出的组件文件?拆分进去的组件应该放在哪里呢?一个常见的错误做法是一股脑放在一个名为components文件夹里,最初搞得这个文件夹特地臃肿。我的倡议是相关联的代码最好尽量聚合在一起。为了让相关联的代码聚合到一起,咱们能够把页面搞成文件夹的模式,在文件夹外部寄存与以后文件相干的组成部分,并将示意页面的组件命名为index放在文件夹下。再在该文件夹下创立components目录,将组成页面的其余组件放在外面。如果一个页面的某个组成部分很简单,外部还须要拆分成更细的多个组件,那么就把这个组成部分也做成文件夹,将拆分出的组件放在这个文件夹下。最初就是组件复用的问题。如果一个组件被多个中央复用,就把它独自提取进去,放到须要复用它的组件们独特的形象层级上。 如下: 如果只是被页面内的组件复用,就放到页面文件夹下。如果只是在以后业务场景下的不同页面复用,就放到以后业务模块的文件夹下。如果能够在不同业务场景间通用,就放到最顶层的公共文件夹,或者思考做成组件库。 对于我的项目文件的组织形式曾经超过本文探讨的领域,我打算放到当前专门出一篇文章说下如何组织我的项目文件。这里只说下页面级别的文件如何进行组织。上面是我罕用的一种页面级别的文件的组织形式:homePage // 寄存以后页面的文件夹 |-- components // 寄存以后页面组件的文件夹 |-- componentA // 寄存以后页面的组成部分A的文件夹 |-- index.(vue|tsx) // 组件A |-- AChild1.(vue|tsx) // 组件a的组成部分1 |-- AChild2.(vue|tsx) // 组件a的组成部分2 |-- ACommon.(vue|tsx) // 只在componentA外部复用的组件 |-- ComponentB.(vue|tsx) // 以后页面的组成部分B |-- Common.(vue|tsx) // 组件A和组件B里复用的组件|-- index.(vue|tsx) // 以后页面复制代码实际上这种组织形式,在形象意义上并不完满,因为通用组件和页面组成部分的组件并没有辨别开来。然而一般来说,一个页面也不会抽出太多组件,为了不便放到一起也不会有太大问题。然而如果你的页面切实简单,那么再创立一个名为common的文件夹也未尝不可。 3.如何用hooks抽离组件逻辑?在hooks呈现之前,曾风行过一个设计模式,这个模式将组件分为无状态组件和有状态组件(也称为展现组件和容器组件),前者负责管制视觉,后者负责传递数据和解决逻辑。但有了hooks之后,咱们齐全能够将容器组件中的代码放进hooks外面。后者不仅更容易保护,而且也更不便把业务逻辑与个别组件辨别开来。在抽离hooks的时候,咱们不仅应该沿用个别函数的抽象思维,如性能繁多,耦合度低等等,还应该留神组件中的逻辑可分为两种:组件交互逻辑与业务逻辑。如何把文章结尾说的视图、交互逻辑和业务逻辑辨别开来,是掂量一个组件品质的重要规范。以一个用户模块为例。一个蕴含查问用户信息,批改用户信息,批改明码等性能的hooks能够这样写:// 用户模块hookconst useUser = () => { // react版本的用户状态const user = useState({});// vue版本的用户状态const userInfo = ref({});// 获取用户状态const getUserInfo = () => {}// 批改用户状态const changeUserInfo = () => {};// 查看两次输出的明码是否雷同const checkRepeatPass = (oldPass,newPass) => {}// 批改明码const changePassword = () => {};return { userInfo, getUserInfo, changeUserInfo, checkRepeatPass, changePassword,}}复制代码交互逻辑的hook能够这么写(为了不便只写vue版本的,大家应该也都看得懂):// 用户模块交互逻辑hooksconst useUserControl = () => { ...

July 29, 2022 · 2 min · jiezi

关于react.js:React报错之组件不能作为JSX组件使用

总览组件不能作为JSX组件应用,呈现该谬误有多个起因: 返回JSX元素数组,而不是单个元素。从组件中返回JSX元素或者null以外的任何值。应用过期的React类型申明。返回单个JSX元素上面是一个谬误如何产生的示例。 // App.tsx// ⛔️ 'App' cannot be used as a JSX component.// Its return type 'Element[]' is not a valid JSX element.// Type 'Element[]' is missing the following properties from type 'ReactElement<any, any>': type, props, keyconst App = () => { return ['a', 'b', 'c'].map(element => { return <h2 key={element}>{element}</h2>; });};export default App;代码示例中的问题是,咱们返回的是一个JSX元素数组,而不是单个JSX元素。 为了解决这种状况下的谬误,咱们必须应用React fragment 或者div元素来包裹数组。 // App.tsxconst App = () => { return ( <> {['a', 'b', 'c'].map(element => { return <h2 key={element}>{element}</h2>; })} </> );};export default App;当初咱们的组件返回了单个JSX元素,这样谬误就解决了。 ...

July 28, 2022 · 2 min · jiezi

关于react.js:安装umi4阻碍一天的问题解决了

umi4曾经公布一段时间了,当初我的项目中还是用的umi3版本,umi3最坑的就是mfsu不会热更新,而且umi4新增了一些性能,所以打算把umi版本升级下。 问题通过 npm create umi,抉择pnpm装置。 报错:dyld: Symbol not found: _SecTrustEvaluateWithError 环境:mac os: 10.12.6node.js: v16.14.2pnpm报错: Packages are hard linked from the content-addressable store to the virtual store. Content-addressable store is at: /Users/keven/Library/pnpm/store/v3 Virtual store is at: node_modules/.pnpmProgress: resolved 1192, reused 1063, downloaded 0, added 1112, donenode_modules/.pnpm/esbuild@0.14.36/node_modules/esbuild: Running postinstall script, failed in 568ms.../esbuild@0.14.36/node_modules/esbuild postinstall$ node install.js│ node:child_process:828│ err = new Error(msg);│ ^│ Error: Command failed: /Users/keven/Documents/personal/code/umi/antd/node_modules/.pnpm/esbuild@0.14.36/node_m│ dyld: Symbol not found: _SecTrustEvaluateWithError│ Referenced from: /Users/keven/Documents/personal/code/umi/antd/node_modules/.pnpm/esbuild@0.14.36/node_modul│ Expected in: flat namespace│ at checkExecSyncError (node:child_process:828:11)│ at Object.execFileSync (node:child_process:866:15)│ at validateBinaryVersion (/Users/keven/Documents/personal/code/umi/antd/node_modules/.pnpm/esbuild@0.14.36│ at /Users/keven/Documents/personal/code/umi/antd/node_modules/.pnpm/esbuild@0.14.36/node_modules/esbuild/i│ status: null,│ signal: 'SIGABRT',│ output: [│ null,│ Buffer(0) [Uint8Array] [],│ Buffer(215) [Uint8Array] [│ 100, 121, 108, 100, 58, 32, 83, 121, 109, 98, 111, 108,│ 32, 110, 111, 116, 32, 102, 111, 117, 110, 100, 58, 32,│ 95, 83, 101, 99, 84, 114, 117, 115, 116, 69, 118, 97,│ 108, 117, 97, 116, 101, 87, 105, 116, 104, 69, 114, 114,│ 111, 114, 10, 32, 32, 82, 101, 102, 101, 114, 101, 110,│ 99, 101, 100, 32, 102, 114, 111, 109, 58, 32, 47, 85,│ 115, 101, 114, 115, 47, 107, 101, 118, 101, 110, 47, 68,│ 111, 99, 117, 109, 101, 110, 116, 115, 47, 112, 101, 114,│ 115, 111, 110, 97,│ ... 115 more items│ ]│ ],│ pid: 15457,│ stdout: Buffer(0) [Uint8Array] [],│ stderr: Buffer(215) [Uint8Array] [│ 100, 121, 108, 100, 58, 32, 83, 121, 109, 98, 111, 108,│ 32, 110, 111, 116, 32, 102, 111, 117, 110, 100, 58, 32,│ 95, 83, 101, 99, 84, 114, 117, 115, 116, 69, 118, 97,│ 108, 117, 97, 116, 101, 87, 105, 116, 104, 69, 114, 114,│ 111, 114, 10, 32, 32, 82, 101, 102, 101, 114, 101, 110,│ 99, 101, 100, 32, 102, 114, 111, 109, 58, 32, 47, 85,│ 115, 101, 114, 115, 47, 107, 101, 118, 101, 110, 47, 68,│ 111, 99, 117, 109, 101, 110, 116, 115, 47, 112, 101, 114,│ 115, 111, 110, 97,│ ... 115 more items│ ]│ }└─ Failed in 569ms ELIFECYCLE Command failed with exit code 1.换yarn试试,同样报错 ...

July 26, 2022 · 4 min · jiezi

关于react.js:记录一次有趣的React项目埋点过程

公司产品有个埋点需要,当用户在点击日志记录时,上报日志列表中最新记录和以后记录的信息,因为组件间间隔比拟远,没方法间接拿到多层之外组件中的数据,因而用了hack的方法解决,记录在此,以飨读者。背景介绍笔者正在参加的我的项目有一个日志记录核心性能,相似于上图所示的告诉核心。产品给的需要如下: 用户点击某条记录时埋点 ——> 须要发送以后的记录类型及创立工夫,及日志列表中最新记录的创立工夫、最新记录与以后记录的距离数。在React中,数据次要是通过单向数据流向子组件传递,仔细分析后发现通过传统形式不好拿。首先用户点击的记录没有最新记录的信息,所以也不会有最新记录的创立工夫,其次,记录是懒加载,所以最新记录与以后记录之间的距离数也没法间接拿。 如果通过重构的形式在组件中传递这些数据必定是能够的,然而要花费很大的代价,且不说波及到多层业务组件层层嵌套,就算是把数据放到Redux中存储,也须要破费比拟多的计算资源,稍有不慎也会导致组件的非必要渲染。 这次应用的hack形式,技术原理并不简单,核心思想是在页面中拿到DOM,并应用DOM节点的原生办法进行计算,失去想要的数据。 拿到最新记录的日志类型和工夫戳与规范html统一,在React中反对应用 data-* 属性来嵌入自定义数据: <div className="item" data-time={item.time} onClick={this.handleClick}>一个DIV节点<div/>比方在下面的div标签中,通过应用data-time属性,将以后记录的time字段绑定到了标签上。绑定当前如何获取呢,同样能够应用浏览器的原生办法,如:document.getElementById()document.querySelectorAll(),这里应用第二种形式演示: //获取到日志记录DOM列表(每一条为一个DOM节点)const itemList = document.querySelectorAll('.item')//获取用户点击的DOM节点在list中的地位const clickedRecord = [].indexOf.call(itemList, e.currentTarget)//获取第一个DOM节点上绑定的time数据const firstItemTime = itemList[0].getAttribute('data-time')简述一下过程:通过日志item独有的className标签拿到日志记录的DOM列表,而后通过鼠标点击对象的currentTarget属性拿到以后点击的日志DOM对象,进而计算以后日志在列表中所处的地位。最新记录的创立工夫通过DOM节点的getAttribute办法拿到绑定的数据。 总结React官网并不举荐间接操作DOM,但间接操作DOM确实能解决很多非凡的业务需要(香啊),所以开发者敌人在闲来无事的时候还是要把DOM的办法捡起来,说不定啥时候就用上了。另外须要阐明的是这只是一个长期的埋点需要,如果是我的项目中比拟外围的性能点,采纳这种形式还须要认真评估。

July 24, 2022 · 1 min · jiezi

关于react.js:react-架构大概流程

之前写了一篇react相干的文章,然而那篇文章大都在介绍代码,对思维架构根本没什么波及。这篇文章始终没有想好怎么写,react外部属实有够简单的。看了好多人对react的架构了解,这里动笔写一下,有不同意见欢送diss.这里首推参考的文章:卡颂大佬的react源码解析 DavidWong的一眼看穿react4步曲 React 为什么应用 Lane 技术计划 这一篇文章可能有不对的中央,后续有新的了解了也会改。 待续。。。

July 20, 2022 · 1 min · jiezi

关于react.js:useInterval

是从GitHub根底上批改而来,这个GitHub上的次要代码 import { useEffect, useRef } from 'react';type Delay = number | null;type TimerHandler = (...args: any[]) => void;/** * Provides a declarative useInterval * * @param callback - Function that will be called every `delay` ms. * @param delay - Number representing the delay in ms. Set to `null` to "pause" the interval. */const useInterval = (callback: TimerHandler, delay: Delay) => { const savedCallbackRef = useRef<TimerHandler>(); useEffect(() => { savedCallbackRef.current = callback; }, [callback]); useEffect(() => { const handler = (...args: any[]) => savedCallbackRef.current!(...args); if (delay !== null) { const intervalId = setInterval(handler, delay); return () => clearInterval(intervalId); } }, [delay]);};export default useInterval;这个版本其实曾经在大部分状况曾经满足了,然而我这个是在可视化大屏编辑器中的轮播表格组件应用,当大屏拖入大量轮播表格时标签页可能会无响应于是就批改成上面这个版本 ...

July 20, 2022 · 2 min · jiezi

关于react.js:从原生-JavaScript-到-React

从头开始了解 React作者:Stéphane Bégaudeau于 2018 年 10 月 1 日 React 是一个用于构建用户界面的 JavaScript 框架。它可用于通过动静操作页面内容来创立 JavaScript 应用程序。浏览器曾经提供了在页面中创立元素的 API,即 DOM,所以老手可能想晓得 React 带来了什么以及它与 DOM 的关系。 原生 JavaScript 和 DOM在 JavaScript 中,就像在大多数编程语言中一样,您将能够拜访具备各种对象和函数的全局范畴,您能够操纵这些对象和函数来构建您的应用程序。在 Web 环境中运行的 JavaScript 应用程序中,您将有权拜访文档对象模型 (DOM) API。如果您在基于节点的应用程序中应用 JavaScript,您将无法访问 DOM,但您能够导入代替实现,例如JSDOM。 DOM 是一个简略的 API,可让您以简直任何您想要的形式操作页面的 HTML 文档。因为全局document 对象,您能够开始应用它。 从 document 这里开始,您能够轻松地创立新元素、批改它们的属性,甚至将它们增加为其余元素的子元素。多亏了 DOM,您能够通过编程形式创立任何 HTML 文档,即便这样做会十分简短。 在上面的示例中,咱们将以编程形式在 HTML 文档中创立一个简略的题目。 <!DOCTYPE html><html> <head> <script src="app.js"></script> </head> <body> <div id="app" /> </body></html>为此,咱们将创立一个h1元素,该元素将插入到 HTML 页面的注释中。 // The document object is accessible since it is in the global scopeconst h1Element = document.createElement('h1');h1Element.setAttribute('class', 'title');const textElement = document.createTextNode('I am Groot');h1Element.appendChild(textElement);// document.getElementById('app') will retrieve the div with the identifier appdocument.getElementById('app').appendChild(element);下面的代码首先创立一个新属性,而后向该元素h1增加一个class带有值为title的新属性。 它还创立一个简略的文本节点并将文本 'I am Groot' 增加为元素h1的子元素。最初,它应用 HTML 文档将 h1 的标签增加到 div 中。app 执行此代码后,生成的 HTML 文档将如下所示: ...

July 20, 2022 · 3 min · jiezi

关于react.js:使用React手写一个手风琴组件

知识点emotion语法react语法css语法typescript类型语法成果让咱们来看一下咱们实现的效果图: 构造剖析依据上图,咱们来剖析一下,一个手风琴组件应该蕴含一个手风琴容器组件和多个手风琴子元素组件。因而,假如咱们实现好了所有的逻辑,并写出应用demo,那么代码应该如下: <Accordion defaultIndex="1" onItemClick={console.log}> <AccordionItem label="A" index="1"> Lorem ipsum </AccordionItem> <AccordionItem label="B" index="2"> Dolor sit amet </AccordionItem></Accordion>依据以上的构造,咱们能够得悉,首先容器组件Accordion会裸露一个defaultIndex属性以及一个onItemClick事件。顾名思义,defaultIndex代表默认开展的子元素组件AccordionItem的索引,onItemClick代表点击每一个子元素组件所触发的事件。而后,咱们能够看到子元素组件有label属性和index属性,很显然,label代表以后子元素的题目,index代表以后子元素组件的索引值,而咱们的Lorem ipsum就是子元素的内容。依据这些剖析,咱们先来实现一下AccordionItem组件。 AccordionItem子组件首先咱们定义好子组件的构造,函数组件写法如下: const AccordionItem = (props) => { //返回元素};子元素组件分成三个局部,一个容器元素,一个题目元素和一个内容元素,因而咱们能够将构造写成如下: <div className="according-item-container"> <div className="according-item-header"></div> <div className="according-item-content"></div></div>晓得了构造之后,咱们就晓得props会有哪些属性,首先是索引index属性,它的类型为string 或者number,而后是判断内容是否开展的属性isCollapsed,它的类型是布尔值,其次咱们还有渲染题目的属性label,它应该是一个react节点,类型为ReactNode,同理,还有一个内容属性即children,类型也应该是ReactNode,最初就是咱们要裸露的事件办法handleClick,它的类型应该是一个办法,因而咱们能够定义如下的接口: interface AccordionItemType { index: string | number; label: string; isCollapsed: boolean; //SyntheticEvent代表react合成事件对象的类型 handleClick(e: SyntheticEvent): void; children: ReactNode;}接口定义好之后,接下来咱们就在接口外面拿值(采纳对象解构的形式),这些值都算是可选的,即: const { label, isCollapsed, handleClick, children } = props;此时咱们的AccordionItem子组件应该是如下: const AccordionItem = (props: Partial<AccordionItemType>) => { const { label, isCollapsed, handleClick, children } = props; return ( <div className={AccordionItemContainer} onClick={handleClick}> <div className={AccordionItemHeader}>{label}</div> <div aria-expanded={isCollapsed} className={`${AccordionItemContent}${ isCollapsed ? ' collapsed' : ' expanded' }`} > {children} </div> </div> );};这里咱们能够应用emotion/css来写css类名款式,代码如下: ...

July 16, 2022 · 3 min · jiezi

关于react.js:动手撸组件系列-1-使用React实现一个Collapse组件

写组件的能力是掂量前端工程师程度的重要指标,不论是根底组件还是业务组件。笔者在闲暇工夫也喜爱写组件,为了帮忙初学者上手写React组件,同时为了分享我在写组件中的教训和想法,决定开设一个系列,即:入手撸组件系列,和大家分享一些公共组件和业务组件的实现形式和实现技巧。 作为这个系列的第一篇文章,分享下如何从零到一实现一个折叠面板(Collapse)组件 Collapse根底UI绘制折叠面板作为一个根底组件,由两局部形成:第一局部是题目区域,第二局部是可折叠区域,点击题目区域能够折叠和开展内容区。为了组件的好看性能够在题目右侧增加一个箭头图标,在开展和折叠的时候使其旋转。 为了升高环境搭建老本,实际采纳create-react-app环境,创立create-react-app开发环境异常简略,只须要在装置node的零碎中执行如下命令 npx create-react-app 项目名称须要留神的是我的项目名必须为英文,create-react-app会主动为咱们创立一个目录。 我的项目创立实现后,在src目录下创立名为Collapse.jsx的文件,输出如下代码:(初学者能够抉择复制) import React, { useState } from "react";import "./style.css";const CollapsablePanel = () => { const [isCollapsed, setIsCollapsed] = useState(true); const togglePanel = () => { setIsCollapsed((prevState) => !prevState); }; return ( <div className="wrapper"> <div className="pannel" onClick={togglePanel}> <div className="heading"> <span>Flower Collapse</span> <svg width="20px" height="25px" viewBox="0 0 1024 1024" style={{ color: '#6495ed' }}><path d="M64 351c0-8 3-16 9-22.2 12.3-12.7 32.6-13.1 45.3-0.8l394.1 380.5L905.7 328c12.7-12.3 33-12 45.3 0.7s12 33-0.7 45.3L534.7 776c-12.4 12-32.1 12-44.5 0L73.8 374c-6.5-6.3-9.8-14.6-9.8-23z" p-id="1705"> </path></svg> </div> <div className="content" > <div className="contentInner" > Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. </div> </div> </div> </div> );};export default CollapsablePanel;接着创立名称为style.css的款式文件 ...

July 15, 2022 · 4 min · jiezi

关于react.js:React中的useId

简介useId是新增的用于生成惟一ID值的hook钩子,次要用于客户端和服务器端应用,同时防止 dehydrate 过程中数据不匹配的问题。 它次要用于与须要惟一 ID 的可拜访性 API 集成的组件库。这解决了 React 17 及更低版本中曾经存在的问题,但在 React 18 中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。 然而,不倡议用于List中作为key应用,列表中的惟一key应该应用List中的数据。 问题React渲染有客户端渲染(CSR)和服务端渲染(SSR)。 假如有如下代码片段: // App.tsxconst id = Math.random();export default function App() { return <div id={id}>Hello</div>}如果利用是CSR(客户端渲染),id是稳固的,App组件没有问题。 但如果利用是SSR(服务端渲染),那么App.tsx会分为以下几步: React在服务端渲染,生成随机id(假如为0.1234),这一步叫dehydrate(脱水);<div id="0.12345">Hello</div>作为HTML传递给客户端,作为首屏内容;React在客户端渲染,生成随机id(假如为0.6789),这一步叫hydrate(注水)。客户端、服务端生成的id不匹配! 原始解决形式: // 全局通用的计数变量let globalIdIndex = 0;export default function App() { const id = useState(() => globalIdIndex++); return <div id={id}>Hello</div>}只有React在服务端、客户端的运行流程统一,那么双端产生的id就是对应的。 然而,随着React Fizz(React新的服务端流式渲染器)的到来,渲染程序不再肯定。 比方,有个个性叫 Selective Hydration,能够依据用户交互扭转hydrate的程序。 当下图左侧局部在hydrate时,用户点击了右下角局部:此时React会优先对右下角局部hydrate: 因而,自增的全局计数变量作为id,不再精确!! 那么,有没有什么是服务端、客户端都稳固的标记呢? 答案是:组件的层次结构。 useId的原理假如利用的组件树如下图:不论B和C谁先hydrate,他们的层级构造是不变的,所以「层级」自身就能作为服务端、客户端之间不变的标识。 比方B能够应用2-1作为id,C应用2-2作为id: function B() { // id为"2-1" const id = useId(); return <div id={id}>B</div>;}如何在一个组件中应用多个useId()?react举荐应用雷同的id+后缀: ...

July 15, 2022 · 1 min · jiezi

关于react.js:搞懂react类组件中的this指向

this指向的规定看两个点: this定义在哪个函数中该函数被谁调用最终this就指向谁 JSX中的this指向class Demo extends Component{ state = { count: 0 } handleClick = () => { this.setState({count: this.state.count+1}) } render(){ return( <> {this.state.count} <button onClick={this.handleClick}>按钮</button> </> ) }}onClick={this.handleClick}中的this: 定义在哪个函数中 定义在render函数中函数被谁调用: render函数被React调用,所以this指向React,又因为React做了一些设置,将this指向Demo类的实例,所以这里的this指向Demo类实例,所以this.handleClick就是 Demo实例.handleClickFunction函数中的this指向class Demo extends Component{ state = { count: 0 } handleClick = function(){ this.setState({count: this.state.count+1}) } render(){ return( <> {this.state.count} <button onClick={this.handleClick}>按钮</button> </> ) }}// 点击按钮报错// Cannot read properties of undefined (reading 'setState')handleClick=function(){ this.setState...)中的this: 定义在哪个函数中: 定义在Demo类的handleClick函数中函数被谁调用: onClick={this.handleClick}是将Demo.handleClick这个函数作为onclick事件的回调函数应用,回调函数执行时没有被调用者js中,函数如果找不到调用者,最初就会在顶层对象中调用,也就是this会指向window对象,但因为应用了ES6语法,ES6语法默认采纳严格模式,严格模式下,this不会指向window,而是undefined,所以才会报错。 ...

July 14, 2022 · 1 min · jiezi

关于react.js:React-Table-表格组件使用教程-排序分页搜索过滤筛选功能实战开发

本文完整版:《React Table 表格组件应用教程 排序、分页、搜寻过滤筛选性能实战开发》 在日常开发中,特地是外部应用的后盾零碎时,咱们经常会须要用表格来展现数据,同时提供一些操作用于操作表格内的数据。简略的表格间接用原生 HTML table 就好,但如果要在 React 中实现一个功能丰富的表格,其实是十分不容易的。 在本站之前的文章《最好的 6 个 React Table 组件具体亲测举荐》 中有提到过 react-table 这个库,如果对这个库不太理解的同学能够先理解一下,这里不再赘述。 简而言之,react-table 是一个十分弱小的库,它与常见的表格组件不同,它不负责渲染 HTML 和 CSS,而是提供了一系列的 hooks 让咱们能够灵便地构建功能强大的表格组件。 因而应用 react-table 进行开发具备肯定的难度,而本文将由浅入深地解说如何在 React 我的项目中应用 react-table 实现各种常见的需要,例如:排序、分页、搜寻过滤筛选等;同时还会联合一个残缺的案例给大家解说如何搭配应用 Material-UI 以及模仿从后端获取数据进行分页等性能。 如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云 ,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API,内置表格等常见的前端组件,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 追随本文你将学到 如何应用 react-table 在 React 中搭建表格组件如何应用 react-table 表格组件进行数据的分页、排序、搜寻过滤筛选react-table 实战案例:手把手教你应用 react-table 表格组件实战分页、排序、搜寻过滤筛选 扩大浏览:《顶级好用的 React 表单设计生成器,可拖拽生成表单》 react-table 装置和应用首先,让咱们先来创立一个 React 我的项目: npx create-react-app react-table-democd react-table-demo而后咱们装置一下 react-table: 接下来咱们通过一个简略的示例,解说如何在 React 我的项目中应用 react-table。 假如咱们有一个订单表: 订单编号姓名收货地址下单日期1596694478675759682蒋铁柱北京市海淀区西三环中路19号2022-07-011448752212249399810陈胜利湖北武汉武昌区天子家园2022-06-271171859737495400477宋阿美湖北武汉武昌区天子家园2022-06-211096242976523544343张小乐北京市海淀区北航南门2022-06-301344783976877111376马国庆北京市海淀区花园桥西北2022-06-121505069508845600364小果广州天河机场西侧停车场2022-06-07咱们应用 react-table 时,须要通过一个叫做 useTable 的 hooks 来构建表格。 ...

July 12, 2022 · 10 min · jiezi

关于react.js:手把手教你快速搭建React组件库

前言无论团队大小,随着工夫的推动,多多少少都会有一些可提取的业务组件,积淀组件库和对应的文档是一条必经之路。 间接进入正题,从 0 到 1 开始搞一个业务组件库(可从正文中生成)。 最终的 Demo 可看这里,请应用 Mac 或者 Linux 终端来运行,windows 兼容性未做验证。 应用到工具这三个工具是后续业务组件库搭建应用到的,须要有肯定的理解: Lerna ,Lerna是一个 Npm 多包管理工具,具体可查看官网文档。Docusaurus,是 Facebook 官网反对的文档工具,能够在极短时间内搭建丑陋的文档网站,具体可查看官网文档。Vite,Vite 是一种新型前端构建工具,可能显著晋升前端开发体验,开箱即用,用来代替 rollup 构建代码能够省掉一些繁琐的配置。初始化我的项目留神 Node 版本须要在 v16 版本以上,最好应用 v16 版本。 初始化的文件构造如下: .├── lerna.json├── package.json└── website假如我的项目 root 文件夹: 第一步,初始化 Lerna 我的项目 $ npx lerna@latest initlerna 会增加 package.json 和 lerna.json。 第二步,初始化 Docusaurus 我的项目(typescript 类型的) $ npx create-docusaurus@latest website classic --typescript第三步,配置 package.json npm run bootstrap 可初始化装置所有分包的依赖包。npm run postinstall 是 npm 钩子命令,在依赖包实现装置后会触发 npm run postinstall 的运行。{ "private": true, "dependencies": { "lerna": "^5.1.4" }, "scripts": { "postinstall": "npm run bootstrap", "bootstrap": "lerna bootstrap" }}第四步,配置 lerna.json ...

July 10, 2022 · 8 min · jiezi

关于react.js:Virtual-DOM-及-Diff-算法

react 模仿实现代码传送门Tiny React 1. JSX 到底是什么应用 React 就肯定会写 JSX,JSX 到底是什么呢?它是一种 JavaScript 语法的扩大,React 应用它来形容用户界面长成什么样子。尽管它看起来十分像 HTML,但它的确是 JavaScript 。在 React 代码执行之前,Babel 会对将 JSX 编译为 React API. <div className="container"> <h3>Hello React</h3> <p>React is great </p></div>// 1 jsx 代码执行前会被转换为 React.createElement 的调用React.createElement( "div", { className: "container" }, React.createElement("h3", null, "Hello React"), React.createElement("p", null, "React is great"));// 2. createElement 返回 Virtual DOM 对象// 3. 依据 Virtual DOM 生成实在的 DOM从两种语法比照来看,JSX 语法的呈现是为了让 React 开发人员编写用户界面代码更加轻松。 Babel REPL 2. DOM 操作问题在古代 web 应用程序中应用 JavaScript 操作 DOM 是必不可少的,但遗憾的是它比其余大多数 JavaScript 操作要慢的多。 ...

July 5, 2022 · 15 min · jiezi

关于react.js:深入浅出React理解-React-生命周期

前言 如果说 JSX 是学习 React 框架必须要理解的一个概念,那么“生命周期”则是紧随其后的第二个须要学习的内容。尽管当初最新的 React 版本都举荐应用函数组件联合 hooks 的形式来组织利用,而且在函数组件中淡化了对生命周期的介绍,然而对于类组件生命周期的学习了解可能帮忙咱们以追根溯源的形式,更全面的建设对 React 框架的观感,同时从底层意识 React 中两个重要的阶段:render 与 commit ,帮忙咱们编写正确且高效的代码。 本次分享会从上面的几个问题登程: 生命周期到底是什么?类组件生命周期函数有哪些,都在什么场景下应用?生命周期函数演变的起因是什么?Hooks 与 生命周期函数的对应关系是什么?React 中的生命周期到底是什么 生命周期(lifecycle)的概念在各个领域中都宽泛存在,狭义来说生命周期泛指自然界和人类社会中各种客观事物的阶段性变动及其法则,在 React 框架中则用来形容组件挂载(创立)、更新(存在)、卸载(销毁)三个阶段。 基本上咱们每个新同学都会被要求通读 React 官网的材料,通过这样的形式建设起对 React 框架大抵的全像。在此过程中应该能察觉到 React 始终在重复的提及两个关键词:虚构 DOM 与 组件。 在后面意识 JSX 的过程中,咱们晓得虚构 DOM 的实质就是通过编译 JSX 失去的一个以 JavaScript 对象模式存在的 DOM 构造形容。在组件初始化阶段,会通过生命周期办法 render 生成虚构 DOM节点,而后通过调用 ReactDOM.render 办法,实现虚构 DOM 节点到实在 DOM 节点的转换。在组件更新阶段,会再次调用 render 办法生成新的虚构 DOM 节点,而后借助Diffing 算法比对两次虚构 DOM 节点的差别,从而找出变动的局部实现最小化的 DOM 更新。所以也能够说虚构 DOM 是 React 外围算法 Diffing 的基石。 组件化是一种优良的软件设计思维,这在 React 框架中失去了很好的体现。React 我的项目中基本上所有的根底单元就是组件,通过组合各种组件构建利用。每个组件既是关闭又是凋谢。关闭体现在组件外部有本人的一套渲染逻辑(state),在没有数据流交互的状况下,组件与组件之间互不烦扰。凋谢则体现在组件间的通信上,基于单向数据流的准则进行通信(props),而数据通信又会对渲染后果造成影响,通过数据这个桥梁,组件之间彼此凋谢,相互影响。关闭与凋谢的个性使得 React 组件具备高度的可维护性与可重用性。 ...

July 5, 2022 · 2 min · jiezi

关于react.js:React技巧之中断map循环

原文链接:https://bobbyhadz.com/blog/react-map-break 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,中断map()循环: 在数组上调用slice()办法,来失去数组的一部分。在局部数组上调用map()办法。遍历局部数组。export default function App() { const employees = [ {id: 1, name: 'Alice', country: 'Austria'}, {id: 2, name: 'Bob', country: 'Belgium'}, {id: 3, name: 'Carl', country: 'Canada'}, {id: 4, name: 'Delilah', country: 'Denmark'}, {id: 5, name: 'Ethan', country: 'Egypt'}, ]; // ️ map() first 2 elements of array return ( <div> {employees.slice(0, 2).map((employee, index) => { return ( <div key={index}> <h2>name: {employee.name}</h2> <h2>country: {employee.country}</h2> <hr /> </div> ); })} </div> );}sliceArray.slice办法不会批改原数组,相同,它会创立一个新数组(原始数组的浅拷贝)。 ...

July 1, 2022 · 2 min · jiezi

关于react.js:react18-createreactapp系列

前言最近在学习react想通过写文章的模式加深了解 这个用的是create-react-app创立的我的项目 前期有空的话会写一篇从0-1用webpack实现我的项目构建 敬请期待吧~小demo是跟着https://gitee.com/shenghaibin... 敲的 1.用create-react-app创立的我的项目npx create-react-app my-demo2.装置我的项目所需依赖npm install react-router-domnpm install mobx mobx-react-lite sass dayjs echarts uuid -Dnpm install react-vant@2.0.0-alpha.32 -D 3.批改index.js入口文件 增加路由console.log('index.js');import React from 'react';import ReactDOM from 'react-dom/client';import './index.css';import App from './App';import reportWebVitals from './reportWebVitals';import { BrowserRouter } from 'react-router-dom'const root = ReactDOM.createRoot(document.getElementById('root'));root.render( <BrowserRouter> <App /> </BrowserRouter>);// If you want to start measuring performance in your app, pass a function// to log results (for example: reportWebVitals(console.log))// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitalsreportWebVitals();4.先来给文件名称设置别名因为react官网默认把webpack配置暗藏起来了,须要运行npm run ejec把webpack的配置显示进去,间接运行npm run eject会报错 须要切换到根目录把仓库初始化一下后找到webpack.config.js文件中的resolve 代码贴在下方了更改完配置文件记得重启下我的项目噢~//根目录下运行git initgit add .git commit -m 'init'npm run eject//webpack.config.jsresolve:{ alias: { '@': path.resolve(__dirname, '../src/'), 'views': path.resolve(__dirname, '../src/views/'), },}5.报错提醒# Using babel-preset-react-app requires that you specify NODE_ENV or BABEL_ENV environment varia因为执行npm run eject关上我的项目配置 我的项目中会有提醒报错 尽管不影响代码失常运行 然而影响好看 须要正文eslintConfig中的配置即可`//package.json"eslintConfig": {"extends": [ "//react-app", "react-app/jest"]},` ...

July 1, 2022 · 1 min · jiezi

关于react.js:webpack从零搭建react应用

在上一篇文章中咱们用webpack与webpack-cli搭建了最简略的前端利用,通常在我的项目中咱们会用vue或者react,咱们看下如何利用咱们本人搭的工程来适配react注释开始... 前置首先咱们要确定,react并不是在webpack中像插件一样装置就能够间接应用,咱们须要反对jsx以及一些es6的一些比拟新的语法,在creat-react-app这个脚手架中曾经帮咱们高度封装了react我的项目的一些配置,甚至你是看不到很多的配置,比方@babel/preset-react转换jsx等。所以咱们须要晓得一个react我的项目须要哪些插件的前提条件,本文次要参考从头开始打造工具链 装置babel相干插件 npm i @babel/core @babel/cli @babel/preset-env @babel/preset-react --save其中babel/core就是能将代码进行转换,@babel/cli容许命令行编译文件,babel/preset-env与@babel/preset-react都是预设环境,把一些高级语法转换成es5 装置好相干插件后,咱们须要在根目录中创立一个.babelrc来让babel告诉那两个预设的两个插件失效 // .babelrc{ "presets": ["@babel/env", "@babel/preset-react]}接下来咱们须要装置在react中的反对的jsx,次要依赖babel-loader来编译jsx npm i babel-loader --save-dev并且咱们须要改下webpack.config.js的loader { module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] }, { test: /\.(png|svg|jpg|gif|jpeg)$/, use: [ { loader: 'file-loader', options: { outputPath: 'assets', name: '[name].[ext]?[hash]' } } ] }, { test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /node_modules/, options: { presets: ['@babel/env'] } } ] },}在react中咱们设置HMR,咱们须要联合new webpack.HotModuleReplacementPlugin(),并且在devServer中设置hot为true module.exports = { ... plugins: [ new HtmlWebpackPlugin({ template: './public/index.html' }), new miniCssExtractPlugin({ filename: 'css/[name].css' }), new webpack.HotModuleReplacementPlugin() ], devServer: { hot: true }}残缺的配置webpack.config.js就曾经ok了 ...

July 1, 2022 · 2 min · jiezi

关于react.js:React技巧之导入组件

总览在React中,从其余文件中导入组件: 从A文件中导出组件。比如说,export function Button() {} 。在B文件中导入组件。比如说,import {Button} from './another-file' 。在B文件中应用导入的组件。命名导入导出上面的例子是从一个名为another-file.js的文件中导入组件。 // ️ named exportexport function BigButton() { return ( <button style={{padding: '2rem 1rem'}} onClick={() => console.log('big button')} > Big button </button> );}// ️ named exportexport const SmallButton = () => { return ( <button onClick={() => console.log('small button')}>Small button</button> );};上面是咱们如何从一个名为App.js文件中导入组件。 // ️ named importimport {BigButton, SmallButton} from './another-file';export default function App() { return ( <div> <BigButton /> <hr /> <SmallButton /> </div> );}如有必要,请确保以后门路指向another-file.js模块。下面的例子假如another-file.js和App.js位于雷同的目录下。 ...

June 30, 2022 · 2 min · jiezi

关于react.js:React技巧之表单提交获取input值

原文链接:https://bobbyhadz.com/blog/react-get-form-input-value-on-submit 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,通过表单提交取得input的值: 在state变量中存储输出控件的值。在form表单上设置onSubmit属性。在handleSubmit函数中拜访输出控件的值。import {useState} from 'react';const App = () => { const [firstName, setFirstName] = useState(''); const [lastName, setLastName] = useState(''); const handleSubmit = event => { console.log('handleSubmit ran'); event.preventDefault(); // ️ prevent page refresh // ️ access input values here console.log('firstName ️', firstName); console.log('lastName ️', lastName); // ️ clear all input values in the form setFirstName(''); setLastName(''); }; return ( <div> <form onSubmit={handleSubmit}> <input id="first_name" name="first_name" type="text" onChange={event => setFirstName(event.target.value)} value={firstName} /> <input id="last_name" name="last_name" type="text" value={lastName} onChange={event => setLastName(event.target.value)} /> <button type="submit">Submit form</button> </form> </div> );};export default App; ...

June 29, 2022 · 2 min · jiezi

关于react.js:React技巧之设置input值

原文链接:https://bobbyhadz.com/blog/react-set-input-value-on-button-click 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,通过按钮点击设置输入框的值: 申明一个state变量,用于跟踪输出控件的值。将onClick属性增加到button元素上。当button被点击时,更新state变量。import {useState} from 'react';const App = () => { const [message, setMessage] = useState(''); const handleChange = event => { setMessage(event.target.value); }; const handleClick = event => { event.preventDefault(); // ️ value of input field console.log('old value: ', message); // ️ set value of input field setMessage('New value'); }; return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> <h2>Message: {message}</h2> <button onClick={handleClick}>Click</button> </div> );};export default App; ...

June 28, 2022 · 1 min · jiezi

关于react.js:H5阻止IOS端橡皮筋效果

我这边是查阅材料,写了个JS版的函数: IOS_STOP_preventDefault() { let startY, endY; const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; const clientHeight = document.documentElement.clientHeight || document.body.clientHeight; const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight; document.addEventListener( 'touchstart', function (e) { startY = e.touches[0].pageY; }, { passive: false } ); document.addEventListener( 'touchmove', function (e) { endY = e.touches[0].pageY; //记录手指触摸的挪动中的坐标 //手指下滑,页面达到顶端不能持续下滑 if (endY > startY && scrollTop <= 0) { e.preventDefault(); } //手指上滑,页面达到底部不能持续上滑 if (endY < startY && scrollTop + clientHeight >= scrollHeight) { e.preventDefault(); } }, { passive: false } ); }当咱们判断以后环境是IOS环境时,在onload/onready/或各种框架生命周期里调用即可原链接https://www.cnblogs.com/cuncu... ...

June 28, 2022 · 1 min · jiezi

关于react.js:React报错Unable-to-preventDefault-inside-passive-event

此问题个别呈现在一些封装的轮播等环境下 解决办法:在touch的事件监听办法上绑定第三个参数{ passive: false },通知浏览器正在调用 preventDefault 来阻止默认滑动行为 代码: dom.addEventListener('touchstart',你的函数, { passive: false })原链接https://www.jianshu.com/p/791...

June 28, 2022 · 1 min · jiezi

关于react.js:React技巧之打开文件输入框

原文链接:https://bobbyhadz.com/blog/react-open-file-input-on-button-click 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,通过点击按钮,关上文件输入框: 在button元素上设置onClick属性。在文件输入框上设置ref属性。当按钮被点击时,关上文件输入框。比如说,inputRef.current.click() 。import {useRef} from 'react';const App = () => { const inputRef = useRef(null); const handleClick = () => { // ️ open file input box on click of other element inputRef.current.click(); }; const handleFileChange = event => { const fileObj = event.target.files && event.target.files[0]; if (!fileObj) { return; } console.log('fileObj is', fileObj); // ️ reset file input event.target.value = null; // ️ is now empty console.log(event.target.files); // ️ can still access file object here console.log(fileObj); console.log(fileObj.name); }; return ( <div> <input style={{display: 'none'}} ref={inputRef} type="file" onChange={handleFileChange} /> <button onClick={handleClick}>Open file upload box</button> </div> );};export default App; ...

June 26, 2022 · 1 min · jiezi

关于react.js:React技巧之发出http请求

原文链接:https://bobbyhadz.com/blog/react-send-request-on-click 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,通过点击事件收回http申请: 在元素上设置onClick属性。每当元素被点击时,收回http申请。更新state变量,并从新渲染数据。如果你应用axios,请向下滚动到下一个代码片段。import {useState} from 'react';const App = () => { const [data, setData] = useState(); const [isLoading, setIsLoading] = useState(false); const [err, setErr] = useState(''); const handleClick = async () => { setIsLoading(true); try { const response = await fetch('<https://reqres.in/api/users>', { method: 'POST', body: JSON.stringify({ name: 'John Smith', job: 'manager', }), headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); if (!response.ok) { throw new Error(`Error! status: ${response.status}`); } const result = await response.json(); console.log('result is: ', JSON.stringify(result, null, 4)); setData(result); } catch (err) { setErr(err.message); } finally { setIsLoading(false); } }; console.log(data); return ( <div> {err && <h2>{err}</h2>} <button onClick={handleClick}>Make request</button> {isLoading && <h2>Loading...</h2>} {data && ( <div> <h2>Name: {data.name}</h2> <h2>Job: {data.job}</h2> </div> )} </div> );};export default App; ...

June 25, 2022 · 2 min · jiezi

关于react.js:React技巧之检查元素是否可见

原文链接:https://bobbyhadz.com/blog/react-check-if-element-in-viewport 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,查看元素是否在视口范畴内: 在元素上设置ref属性。应用IntersectionObserver API来跟踪元素是否与视口相交。import {useEffect, useRef, useState, useMemo} from 'react';export default function App() { const ref1 = useRef(null); const ref2 = useRef(null); const isInViewport1 = useIsInViewport(ref1); console.log('isInViewport1: ', isInViewport1); const isInViewport2 = useIsInViewport(ref2); console.log('isInViewport2: ', isInViewport2); return ( <div> <div ref={ref1}>Top div {isInViewport1 && '| in viewport ✅'}</div> <div style={{height: '155rem'}} /> <div ref={ref2}>Bottom div {isInViewport2 && '| in viewport ✅'}</div> </div> );}function useIsInViewport(ref) { const [isIntersecting, setIsIntersecting] = useState(false); const observer = useMemo( () => new IntersectionObserver(([entry]) => setIsIntersecting(entry.isIntersecting), ), [], ); useEffect(() => { observer.observe(ref.current); return () => { observer.disconnect(); }; }, [ref, observer]); return isIntersecting;}该示例向咱们展现了,如何查看元素是否在视口范畴内。IntersectionObserver API使咱们可能查看一个给定的元素是否与文档相交。 ...

June 24, 2022 · 1 min · jiezi

关于react.js:React自定义hook之useClickOutside判断是否点击DOM之外区域

最近在开发业务需要的时候,有一个场景是点击弹窗之外的区域后,执行某些操作。比方咱们罕用的github左上角的搜寻框,当点击了搜寻框之外的区域当前,搜寻框就会主动勾销搜寻并收缩起来。 通过调研发现应用useRef+浏览器事件绑定能够实现这一需要,并且能够将这一性能形象为自定义hook。 本文将首先介绍如何用传统形式实现这一需要,而后介绍如何形象成自定义hook,最初联合typescript类型,欠缺这一自定义hook。 实现检测点击对象外区域import React, { useEffect, useRef } from "react";const Demo: React.FC = () => { // 应用useRef绑定DOM对象 const domRef = useRef<HTMLDivElement>(null); // 组件初始化绑定点击事件 useEffect(() => { const handleClickOutSide = (e: MouseEvent) => { // 判断用户点击的对象是否在DOM节点外部 if (domRef.current?.contains(e.target as Node)) { console.log("点击了DOM外面区域"); return; } console.log("点击DOM里面区域"); }; document.addEventListener("mousedown", handleClickOutSide); return () => { document.removeEventListener("mousedown", handleClickOutSide); }; }, []); return ( <div ref={domRef} style={{ height: 300, width: 300, background: "#bfa", }} ></div> );};export default Demo;代码不难理解,首先咱们在函数式组件外面写了一个长度和宽度都是300像素的正方形,而后创立了一个名为domRef的对象将其绑定到dom节点上,最初在useEffect钩子外面申明handleClickOutSide的办法判断用户是否点击了指定的DOM区域,并应用document.addEventListener办法增加事件监听,组件卸载时清理事件监听。在实现的过程中,最外围的是利用了Ref对象上的contains办法,通过钻研发现,Node.contains办法是浏览器的原生办法,其次要的作用是判断传入的DOM节点是否为该节点的后辈节点。 ...

June 24, 2022 · 2 min · jiezi

关于react.js:React技巧之处理tab页关闭事件

原文链接:https://bobbyhadz.com/blog/react-handle-tab-close-event 作者:Borislav Hadzhiev 注释从这开始~ 总览在React中,解决浏览器tab页敞开事件: 应用useEffect钩子增加事件监听器。监听beforeunload事件。在行将卸载tab页时,会触发beforeunload事件。import {useEffect} from 'react';const App = () => { useEffect(() => { const handleTabClose = event => { event.preventDefault(); console.log('beforeunload event triggered'); return (event.returnValue = 'Are you sure you want to exit?'); }; window.addEventListener('beforeunload', handleTabClose); return () => { window.removeEventListener('beforeunload', handleTabClose); }; }, []); return ( <div> <h2>hello world</h2> </div> );};export default App;咱们在useEffect钩子中为window对象增加了一个事件监听器。咱们为useEffect钩子传递一个空的依赖数组,所以只会当组件挂载时运行。 beforeunload当窗口或者tab页行将被卸载时,beforeunload事件会被触发。这时,页面依然是可见的,事件依然是能够勾销的。 这使咱们可能关上一个对话框,询问用户是否真的想来到该页面。用户能够确认并导航到新的页面,或者勾销导航。须要留神的是,并不确定事件会被触发。比如说,用户能够在其浏览器设置中禁用弹出窗口。 咱们应用addEventListener办法在window对象上增加一个事件监听器。该办法承受的第一个参数是要监听的事件的类型,第二个参数是一个函数,当指定类型的事件产生时被调用。 咱们从useEffect钩子返回的函数在组件卸载时被调用。咱们应用removeEventListener办法来移除咱们之前注册的事件监听器。 清理步骤很重要,因为咱们要确保咱们的应用程序中没有任何内存透露。 总结咱们介绍了如何解决tab页敞开事件,次要是通过beforeunload事件进行监听,并在回调事件里做相应的逻辑解决。须要留神的是,须要在组件卸载时,勾销对事件的监听,避免内存透露状况的产生。

June 23, 2022 · 1 min · jiezi

关于react.js:React-Native如何做线上错误与性能监控

一、前言咱们每个人可能都会遇到这样的问题:即咱们的代码在本地测试时没有问题,然而一上线运行,就会遇到各种奇奇怪怪的线上 Bug。因为本地测试场景并不能全面笼罩,对于这种线上的Bug,最无效的伎俩就是搭建线上监控零碎,而后再进行批改。所以,不论是如许小的零碎,线上谬误与性能监控是必须具备的能力。 通常,从头搭建和迭代一个监控零碎的老本是十分高的,如果你也有线上谬误和性能的监控需要,然而公司外部又没有现成的监控零碎,那我的倡议是间接用 Sentry。Sentry译为哨兵,是一个可能实时监控生产环境上的监控零碎,一旦线上版本产生异样回立即会把报错的路由门路、谬误所在文件等详细信息告诉给相干人员,而后开发人员就能够利用错误信息的堆栈跟踪疾速定位到须要解决的问题。Sentry 提供了一个演示 Demo,你能够间接关上它,体验下它有哪些具体的性能。 而且 Sentry 的代码是开源的,它既反对开发者本人搭建,也反对付费间接应用。如果想本人搭建的话,Sentry 后端服务是基于 Python 和 ClickHouse 创立的,须要本人应用物理机进行搭建。不过,对于小团队来说,间接应用付费服务即可,能够省下麻烦的保护老本。 二、根本信息收集首先,咱们要明确一点,解决线上问题和解决本地问题的思路是不一样的,即通过复现谬误门路,而后定位问题并解决问题。当然,在定位问题的过程中也能够应用调试工具,比方 Flipper,它有打日志、打断点等性能。 不过,在解决线上问题时,咱们并不能重复尝试和应用调试工具,此时就须要相似 Sentry 这样的线上监控工具来帮忙咱们排查问题。如果咱们对 Sentry 线上监控 SDK 的比拟理解的话,你会发现它次要收集了三类线上数据: 设施信息;报错日志;利用性能数据。所以接下来,咱们要先一起实现一个繁难监控 SDK,把这些信息都收集下来,这样你就可能明确 Sentry 线上监控 SDK 的底层原理了。当然,以上信息的收集必须恪守网信办的 《网络数据安全管理条例(征求意见稿)》,像设施惟一标示 IMEI、用户地理位置、运营商编号这些信息,咱们是不能收集的,如果须要收集,是须要通过用户受权批准的。你可能会问,不能收集设施惟一标示 IMEI,那咱们怎么晓得用户是谁啊?代替 IMEI 计划就是 UUID。UUID 的全称是 Universally Unique Identifier,翻译过去就是通用惟一识别码,它是通过一个随机算法生成的 128 位的标识。生成两个反复 UUID 概率靠近零,能够忽略不计,因而咱们能够应用 UUID 代替与用户设施绑定的 IMEI 作为惟一标示符,该办法也是业内的通用计划之一。 为了收集设施惟一UUID,咱们能够应用 UUID 算法配合 AsyncStorage 或 MMKV 生成一个用户 ID,代码如下: import uuid from 'react-native-uuid';import { MMKV } from 'react-native-mmkv'// 用户惟一标示let userId = ''const storage = new MMKV()const hasUserId = storage.contains('userId')// 用户已经关上过 Appif(hasUserId) {  userId = storage.get('userId')} else {  // 用户第一次关上 App  userId = uuid.v4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'    storage.set('userId', userId)}如上代码中的 react-native-uuid 是 UUID 算法的 React Native 版本。react-native-mmkv 是长久化键值存储工具,MMKV 的性能比 AsyncStorage 更好,所以我这里就用它代替了 AsyncStorage。生成用户惟一标示 userId 的思路是这样的:每次开打 App 时,先应用 storage.contains(‘userId’) 判断一下在 MMKV 长久化键值存储核心是否存在 userId。如果 userId 的键值对不存在,那么该用户是第一次关上 App,这时应用 uuid.v4 算法生成一个 uuid 作为用户的惟一标示,并应用 userId 作为键名,调用 storage.get 办法将该键值对存在 MMKV 中。如果存在 userId 的键值对,那么该用户是就不是第一次关上 App 了,这时间接应用 userId 这个键名,将第一次关上 App 生成的用户惟一标示,从 MMKV 中读出来就能够了。 ...

June 20, 2022 · 5 min · jiezi

关于react.js:Redux-compose

读的比拟好的一篇文章: https://www.jianshu.com/p/c9d... export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args)))}compose(f1, f2, f3, f4)(args) 执行程序是 : f1(f2(f3(f4(args))))

June 20, 2022 · 1 min · jiezi

关于react.js:通过一道题来看React事件模型

上面代码输入什么const MainApp = () => { const parentRef = useRef(); const childRef = useRef(); const parentClickFun = useCallback(() => { console.log('react parent'); }, []); const childClickFun = useCallback(() => { console.log('react child'); }, []); useEffect(() => { document.addEventListener('click', () => { console.log('document'); }); parentRef.current?.addEventListener('click', () => { console.log('dom parent'); }); childRef.current?.addEventListener('click', () => { console.log('dom child'); }); }, []); return ( <div ref={parentRef} onClick={parentClickFun}> <div ref={childRef} onClick={childClickFun}> 事件执行程序 </div> </div> );};执行后果: ...

June 20, 2022 · 1 min · jiezi

关于react.js:reactquery手把手教程③并行请求及依赖请求

并行申请及依赖申请写在后面因为国内较少有比拟零碎的react-query教程,因而笔者联合官网文档以及官网课程的内容,心愿写一个较为全面的教程。本文将以各种例子作为切入点,尽可能通俗易懂地解说相干知识点。如果有谬误,还请大家在评论区指出,笔者会尽快改过。 目录入门react-query 已于2022-06-04更新深刻查询键及查问函数 已于2022-06-08更新并行申请及依赖申请 已于2022-06-19更新并行申请什么是并行申请?在日常开发中,前端申请后端接口时,通常会申请多个接口。比方上面的react-query代码:   const usersQuery = useQuery(['users'], fetchUsers)   const teamsQuery = useQuery(['teams'], fetchTeams)   const projectsQuery = useQuery(['projects'], fetchProjects)下面的示例中,申请了用户列表,团队列表,我的项目列表,此时的接口申请就是并行申请,每个申请互不烦扰(你同样能够在数据库查问中,看到相干的概念,Google一下Parallel Queries)。谁先申请到数据,就显示哪一项数据。 假如当初有一个需要:别离展现github用户的仓库和代码片段列表 此时咱们须要申请两个接口 获取用户仓库列表: https://api.github.com/users/{username}/repos获取用户代码片段列表: https://api.github.com/users/{username}/gists对这两个接口别离同时进行申请,哪个接口先返回了数据,就显示哪个接口的数据: 点我查看在线演示 import { useQuery } from "react-query";const ReposAndGists = ({ username }) => {  const reposQuery = useQuery(   ["repos", username],   () => {      return fetch(        `https://api.github.com/users/${username}/repos`     )     .then((res) => res.json())   } );  const gistQuery = useQuery(   ["gists", username],   () => {      return fetch(        `https://api.github.com/users/${username}/gists`     )     .then((res) => res.json())   } );  return (    <div>      <h2>仓库列表</h2>     {reposQuery.isLoading && <p>加载仓库列表中...</p>}     {reposQuery.isError && (        <p>加载仓库列表产生谬误: {reposQuery.error.message}</p>     )}     {reposQuery.data && (        <ul>         {reposQuery.data.map((repo) => (            <li key={repo.id}>{repo.name}</li>         ))}        </ul>     )}      <h2>代码片段列表</h2>     {gistQuery.isLoading && <p>加载代码片段列表中...</p>}     {gistQuery.isError && (        <p>加载代码片段列表谬误: {gistQuery.error.message}</p>     )}     {gistQuery.data && (        <ul>         {gistQuery.data.map((gist) => (            <li key={gist.id}>{gist.description}</li>         ))}        </ul>     )}    </div> );};另外一种状况是,心愿对两个接口进行合并申请,等到两个接口都返回数据时,再向用户展现内容 ...

June 19, 2022 · 4 min · jiezi

关于react.js:zustand状态管理源码解析一

对于react状态管理工具库有很多,比拟闻名的有redux、mobx,这两款工具库应用相对来说比拟宽泛,明天咱们所要理解的是一个比拟小而精美的状态管理工具库zustand,截止目前为止有17+的start,最次要的是这个库提供的store写法简略,不在像以往咱们通过state、action、dispatch等等一系列繁琐的操作进行状态治理,同时也能够脱离组件应用,让咱们一起读一读源码理解一下他的状态管理机制; 本次咱们先从3.x版本解读,4.x版本作者还在rc阶段,等最终公布后咱们在持续追加4.x版本的改变解析; 1、create创立store,与应用 这个工具库相对来说很简略,咱们间接应用 import create from 'zustand'interface BearStore { bears: number, increasePopulation: () => void, removeAllBears: () => void}const useBearStore = create<BearStore>(set => ({ bears: 0, increasePopulation: () => set(state => { console.log('用于debug') return { bears: state.bears + 1 } }), removeAllBears: () => set({ bears: 0 })}))我的项目中的应用方法 import useBearStore from './BearStore'const Home: React.FC = () => { const bearStore = useBearStore() return <div> 内容信息 <div>{ bearStore.bears }</div> <button onClick={bearStore.increasePopulation}>减少</button> <button onClick={bearStore.removeAllBears}>重置</button> </div>} 在应用咱们对于create函数的应用做一个具体的阐明,咱们解读一下源码对于create函数的形容 ...

June 17, 2022 · 3 min · jiezi

关于react.js:怎样写个sdk嵌套到别的项目

需要:客户的我的项目须要用咱们的性能,且须要提供个modal嵌入到他们的我的项目里,在他们的table中点击对应的item,弹出我提供的modal。 解决方案我的项目应用cra构建,应用webpack的library导出为一个库给第三方应用, 官网教程创立 library output: { library: 'Geek' }这样的话客户就能够间接window.Geek.showModal()调用咱们的弹窗,index.js import React from 'react';import ReactDOM from 'react-dom';import App from './App';import './index.css';import 'antd/dist/antd.less';import { defaultAuditRecord } from 'constants/configration';const modalState = {};const createContainer = () => { const container = document.createElement('div'); container.setAttribute('id', 'container'); document.body.append(container);};const renderApp = (showBtn) => { ReactDOM.render( <React.StrictMode> <App modalState={modalState} showBtn={showBtn} /> </React.StrictMode>, document.getElementById('container') );};// 渲染sdkexport const mount = (showBtn) => { createContainer(); renderApp(showBtn);};// 显示弹窗export const showModal = (record = defaultAuditRecord, callback = () => {}) => { // record 为{id:1,user:""} modalState.showModal(record, callback);};export const closeModal = () => { modalState.closeModal();};// mount(true);客户调用sdk ...

June 16, 2022 · 1 min · jiezi

关于react.js:解读-React-useEvent-RFC

谈谈 React 的新提案:useEvent2022 年 5 月 5 日,Dan Abramov 在 React RFC 上提交了一个新 hook 的提案:useEvent。其目标是返回一个永远援用不变(always-stable)的事件处理函数。 没有 useEvent 时咱们如何写事件函数首先咱们来看一下这段代码 function Chat() { const [text, setText] = useState(""); const onClick = () => { sendMessage(text); }; return <SendButton onClick={onClick} />;}为了拜访最新的 state,onClick在每次Chat组件产生更新时,都会申明一个新的函数(援用变动),这会导致SendButton组件每次都承受一个新的 prop,React 的比拟两个组件节点是否要 diff 前,会对 props 做浅比拟(Object.is),所以每次 props 无意义的变动显然是对 diff 性能不利的。 同时它还会毁坏你的 memo 优化,比方你的SendButton做了如下设计: const SendButton = React.memo(() => {});这时你可能会想到应用useMemo或者useCallback来优化父组件的onClick函数 function Chat() { const [text, setText] = useState(""); const onClick = useCallback(() => { sendMessage(text); }, [text]); return <SendButton onClick={onClick} />;}然而这样当text变动时,援用还是会变动,仍然会带来子组件的不必要更新,设计不当甚至会触发子组件 useEffect 的 re-fired。SendButton基本不关怀text的变动。而且当函数非常复杂时,可能会漏写依赖(当然你能够通过 eslint 来保障),导致每次应用的都是初始 state,从而造成难以追踪的 bug。 ...

June 15, 2022 · 3 min · jiezi

关于react.js:react-vite-testinglibrary单测环境构建

业务复杂多变迭代疾速,加上编写单测其实是消耗肯定工夫去做的,可能很多人认为编写单元测试是一件吃力不讨好的事儿,不会在我的项目中被动的去做单元测试,一两年前笔者也是这样的一种心态,对于单测不屑一顾,然而随着看的书多了,学习的货色多了,明确了单测可有无效的保障咱们一些外围性能的正确性,同样能够反推咱们的设计一些通用性能是否全面,再者也能够在咱们改变一些性能后,校验原有性能的正确性,说这么多,还须要大家本人写起来单测,一个货色好不好,只有用起来了才晓得,在vite下配置jest单测代码一上传至git,有趣味的敌人,能够点此查阅; (1)、测试项目筹备 如果咱们通过creat-react-app创立我的项目会间接内置@testing-library/react,能够开箱即用,然而这里咱们通过vite形式创立的react我的项目,vite构建的我的项目,默认是没有单测的,而后一步步欠缺test构建,这样做的益处呢就是咱们本人相熟配置构建流程,脱离cli脚手架工具,自在搭配; 1、应用vite创立一个空白我的项目pnpm create vite react-test-example -- --template react-ts2、装置react单测相干依赖pnpm add @testing-library/react @testing-library/jest-dom jest -D3、pnpm jest --init生成jest配置文件 上面咱们就对于配置我的项目做个阐明 第一:咱们先设置匹配那些文件作为test文件 testMatch: [ '<rootDir>/src/**/__tests__/**/*.{spec,test}.{js,jsx,ts,tsx}', '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}', '<rootDir>/__test__/**/*.{spec,test}.{js,jsx,ts,tsx}',],第二步:配置我的项目单测文件类型配置,留神这个配置内容是从左到右执行去查看匹配的,所以如果是ts主导的我的项目,咱们就将ts类型文件放在最后面; moduleFileExtensions: [ 'ts', 'tsx', 'js', 'jsx' ]第三步:配置文件文件、门路解析方法,执行这个步骤之前,咱们须要对于文件解析工具进行装置,具体如下: 1、装置pnpm add identity-obj-proxy -D解决css文件2、对于jest单测文件,因为jest是运行在v8引擎中,也就是会以nodejs环境中来去执行,所以对于文件都要本义操作,惯例有两种形式,第一种ts tsx形式写的单测,咱们能够选中用ts-jest形式疾速解决,第二种形式便是通过babel这种形式配置(繁琐一点),当然说道这儿了,咱们得提一嘴明天我这里找到的另一种形式,那就是基于swc的计划,这套计划劣势(我在理论我的项目亲测)就是执行jest单测文件效率会快过下面两种,速度快的不是一星半点,所以我举荐的用swc这套形式;3、基于第二步,咱们装置swc单测相干工具内容pnpm add @swc/core @swc/jest -DmoduleNameMapper: { '^.+\\.module\\.(css|sass|scss|less)$': 'identity-obj-proxy', '\\.svg$': 'identity-obj-proxy', // webpack or vite 等编译工具中波及到的别名辨认},transform: { '^.+\\.(js|jsx|ts|tsx)$': ["@swc/jest"],},transformIgnorePatterns: [ '[/\\\\]node_modules/(?!(antd)/)[/\\\\].+\\.(js|jsx|ts|tsx)$',],第四步:以上步骤针对于一般测试文件,如果咱们须要对组件相干测试,咱们就须要配置testEnvironment,当初咱们我的项目上应用最新版本的jest后(jest 28 之后的版本),提醒装置的是jest-environment-jsdom,咱们装置后,依照上面配置; testEnvironment: 'jsdom',第五步:下面步骤咱们实现根本版本的jest配置,具体对于coverage等等这些配置能够查看官网,还有setupFiles相干配置依据具体应用状况减少,后续咱们应用@testing-library/react进行,组件测试都须要依赖@testing-library/js-dom所以咱们就间接设置setupFilesAfterEnv,将每个单测都须要的公共内容对立增加,具体如下: // ./jest/setupJestDom.tsimport '@testing-library/jest-dom'// 调整jest.config.js, 减少以下内容 setupFilesAfterEnv: [ '<rootDir>/jest/setupJestDom.ts' ],第六步: 每次执行结束后,不主动清理单测缓存,这样执行效率会快 ...

June 15, 2022 · 2 min · jiezi

关于react.js:React-Fiber架构原理

一,概述在 React 16 之前,VirtualDOM 的更新过程是采纳 Stack 架构实现的,也就是循环递归形式。这种比照形式有一个问题,就是一旦工作开始进行就无奈中断,如果利用中组件数量宏大,Virtual DOM 的层级就会比拟深。如果主线程被长期占用,就会阻塞渲染,造成卡顿。为了防止这种状况,须要执行更新操作时不能超过16ms,如果超过16ms,就须要先暂停,让给浏览器进行渲染操作,后续再继续执行更新计算。 而Fiber架构就是为了反对“可中断渲染”而创立的。在React中,fiber tree是一种数据结构,它能够把虚构dom tree转换成一个链表,从而能够在执行遍历操作时反对断点重启,示意图如下。 二、Fiber原理Fiber 能够了解为是一个执行单元,也能够了解为是一种数据结构。 2.1 一个执行单元Fiber 能够了解为一个执行单元,每次执行完一个执行单元,react 就会查看当初还剩多少工夫,如果没有工夫则将控制权让进来。React Fiber 与浏览器的外围交互流程如下图: 能够看到,React 首先向浏览器申请调度,浏览器在一帧中如果还有闲暇工夫,会去判断是否存在待执行工作,不存在就间接将控制权交给浏览器;如果存在就会执行对应的工作,执行实现后会判断是否还有工夫,有工夫且有待执行工作则会继续执行下一个工作,否则将控制权交给浏览器执行渲染。 所以,咱们能够将Fiber 了解为一个执行单元,并且一个执行单元必须是一次实现的,不能呈现暂停,并且这个小的执行单元在认为执行完后能够移交控制权给浏览器去响应用户,从而晋升渲染的效率。 2.2 一种数据结构在官网的文档介绍中,Fiber 被解释为一种数据结构,即咱们熟知的链表。每个 Virtual DOM 都能够示意为一个 fiber,如下图所示,每个节点都是一个 fiber。 通常,一个 fiber包含了 child(第一个子节点)、sibling(兄弟节点)、return(父节点)等属性,React Fiber 机制的实现,就是依赖于下面的数据结构。 2.3 Fiber链表构造Fiber构造是应用的是链表,精确的说是单链表树结构,详见ReactFiber.js源码,上面咱们就看下Fiber链表构造,以便后续更好的了解 Fiber 的遍历过程。 以上每一个单元都蕴含了payload(数据)和nextUpdate(指向下一个单元的指针),定义构造如下: class Update { constructor(payload, nextUpdate) { this.payload = payload //payload 数据 this.nextUpdate = nextUpdate //指向下一个节点的指针 }}接下来定义一个队列,把每个单元串联起来,其中定义了两个指针:头指针firstUpdate和尾指针lastUpdate,作用是指向第一个单元和最初一个单元,并退出了baseState属性存储React中的state状态。 class UpdateQueue { constructor() { this.baseState = null // state this.firstUpdate = null // 第一个更新 this.lastUpdate = null // 最初一个更新 }}接下来定义两个办法:插入节点单元(enqueueUpdate)、更新队列(forceUpdate)。插入节点单元时须要思考是否曾经存在节点,如果不存在间接将firstUpdate、lastUpdate指向此节点即可。更新队列是遍历这个链表,依据payload中的内容去更新state的值 ...

June 10, 2022 · 3 min · jiezi

关于react.js:Recoil-新一代的-React-函数式编程-状态管理工具

我为什么要用 Recoil?起因是最近重构了一个 props 传递层级十分深,组件之间状态通信十分频繁的详情页面。整个代码梳理下来,很难保护,重构时思考,做组件细分,把数据单拎进去,对数据做一个涣散治理。 比照了下之前用过的 Redux、Mobx 感觉有点重,因为我的项目 纯 ts + Func hooks 模式重构,利用这两种比拟惯例的状态管理工具有两个弊病: 对于我的项目代码侵入比拟大,要编写大量的状态治理代码(dispatch、action、reducer)因为是内部库,它们并不能拜访 React 外部的调度程序次要还是感觉这两个库,对于我的项目应用来说,有点重了,没必要为了一个不算很简单的数据管理和通信引入并不算小的 npm 依赖包。起初思考用 Context 来解决,然而多个组件订阅要写多个 Provider 或者有一个根组件的 Provider 来接入数据,这就有会导致很多不必要的重绘和代码量。刚好有共事提了一嘴 Recoil(fb 本人为 react 提供的状态管理工具库),看了下材料,感觉跟本人的我的项目符合度还不错,遂试用了下,成果不错。 简略的介绍下 RecoilRecoil是FaceBook公司提出的状态治理计划(个人感觉像是给 react Func Comps 量身打造的轻量级状态管理工具)。咱们都晓得React强调的是immuteable,而Recoil强调的同样也是immuteable,immuteable给带来的益处就是加强组件整体的利用性能。对于 immuteable 不是很分明的,倡议查阅相干文档,这里不做论述。 Recoil采纳扩散治理原子状态的设计模式. Recoil提出了一个新的治理状态单位Atom(原子化),它是可更新和订阅的,当一个Atom更新之后,每个订阅它的组件都会与之更新从新渲染,如果多个组件应用同一个Atom,那么这些组件将会共享他们的状态。 从上图不难看出,它的核心理念是原子化拆分数据,通过订阅公布的模型对数据进行治理。 Recoil根底初始化应用Recoil的组件须要应用RecoilRoot组件包裹起来 import React from 'react';import { RecoilRoot } from 'recoil';function App() { return ( <RecoilRoot> <CharacterCounter /> </RecoilRoot> );}定义状态下面咱们曾经提到了 Atom 的概念, Atom 是一种新的状态,然而和传统的 state 不同,它能够被任何组件订阅,当一个 Atom 被更新时,每个被订阅的组件都会用新的值来从新渲染。 export const pageInfoState = atom({ key: 'pageInfoState', default: {}});其中 key 必须在 RecoilRoot 作用域内惟一。default 定义默认值。 ...

June 9, 2022 · 2 min · jiezi

关于react.js:亚马逊云科技向你发出召唤游戏开发者集合

「关注」并「星标」咱们, 每天接管对于亚马逊云科技的最新资讯! 世界上90%的大型游戏公司 都在应用的技术是什么?在解答这个问题之前,咱们想请作为游戏开发者的您先答复几个问题: 上述问题, 亚马逊云科技都能够帮您解决! 想要简化简约的流程,迅速构建游戏? 没问题!亚马逊云科技提供的虚构工作站、共享云存储和云渲染的能力能够帮您减速实现平凡创意,您还能够应用亚马逊开源游戏引擎Open 3D Engine打造画面精美绝伦的大型3D游戏。 既要保障玩家体验, 又要升高游戏运行保护老本? 没问题!亚马逊云科技遍布寰球的基础设施能够为世界各地的玩家提供低提早、不间断的游戏体验,同时还内置了Shield Advance能力,以保障经营平安。亚马逊云科技还提供了Local Zone、Outposts和Wavelength等不同档次的计算服务,高弹性、低成本,并且进一步晋升了玩家游戏体验。 想要玩转推广,让游戏增长一飞冲天? 没问题!无论是利用亚马逊Twitch给更多“云玩家”带来沉迷感,还是利用亚马逊云游戏平台Luna真正让玩家在云上开启体验,亚马逊云科技都为游戏增长提供了更多可能性。 想要玩转数据, 让游戏失去继续稳固的增长? 没问题!在亚马逊寰球生态中,还有诸如TapTap、网易易盾、数数科技、行者AI这样的客户与合作伙伴,能够提供弱小的游戏剖析、大数据、AI、机器学习、实时经营等能力,帮忙您更加轻松地了解、倒退和保留玩家。 总而言之,从游戏的构建、运行到增长,亚马逊云科技与咱们的生态合作伙伴能够为全游戏生命周期提供助力,而这也正是寰球90%大型游戏公司的抉择。 您是否想成为他们中的一员呢? 6月16日 一年一度的亚马逊云科技游戏开发者大会行将在线上举办。届时,亚马逊云科技将携手Twitch、FunPlus、心动网 络、哈比游戏、念力科技、金科文化、GKD游戏工作室、TapTap、数数科技、网易易盾、汇量科技以及行者AI等诸多业内出名公司的专家,通过一场主题演讲、三场分论坛、十五场专题演讲,围绕构建、运行、增长的全游戏生命周期,深度解读平凡游戏背地的技术源能源。 扫描下方二维码,即可立即报名流动! ↓↓↓↓↓↓ 2022 亚马逊云科技 游戏开发者大会亮点领先看 流动具体议程如下 ↓ 马上点击“浏览原文” 摸索更多亚马逊云科技游戏开发者大会内容 让咱们独特见证亚马逊的一小步 云计算的一大步 别忘了"分享、在看、点赞 "三连哟

June 9, 2022 · 1 min · jiezi

关于react.js:reactroutermiddlewareplus开源啦-基于reactrouter-v6的零成本式路由权限解决方案

一、你的苦恼~~你还在为react-router的路由权限管制而懊恼吗? 你还在翻遍了社区react路由权限相干文章发现都是V4、V5版本的而懊恼吗? 你还在为自行适配react-router v6版本的权限步骤繁冗,多重鉴权逻辑嵌套而懊恼吗? 他来了!他来了!他带着礼物走来了!react-router-middleware-plus专为解决你的懊恼而生! 二、react-router-middleware-plusreact-router-middleware-plus是基于react-router v6的路由权限配置化解决方案,引入中间件middleware的概念,零老本式路由权限解决方案。 路由组件申明: /** * @method checkLogin * @description 鉴权-登录*/const checkLogin = () => { // 获取登录信息 const isLogin = !!localStorage.getItem('username') if (!isLogin) { navigate('/login', { replace: true }) // 未通过鉴权,返回false return false; } // 通过鉴权,返回true return true}/** * @method checkRole * @description 鉴权-用户角色*/const checkRole = () => { // 依据本人的页面,判断解决,async/await异步拉取用户数据即可。 const isAdmin = localStorage.getItem('role') === 'admin'; if (!isAdmin) { navigate('/', { replace: true }) // 未通过鉴权,返回false return false; } // 通过鉴权,返回true return true}/** * @description 路由配置 * */const routesConfig = [ { path: '/', key: 'index', element: <App></App>, children: [ { index: true, key: 'home', element: <Home></Home> }, { path: 'admin', key: 'admin', // 中间件,容许配置一个或多个 middleware: [ checkLogin, checkLogin, // auth3 // ... ], element: <Admin></Admin> } ] }, { path: '/login', key: 'login', element: <Login></Login> },]middleware: ...

June 9, 2022 · 2 min · jiezi

关于react.js:threejs-实践3D渲染

需要剖析因为业务外面须要可能渲染上传后的3D模型数据,本意是须要依据不同的数据格式,反对不同的渲染的,因而想到了应用 three.js 来实现这个性能,原本想间接在网上借鉴一下大佬的内容,因为咱们的技术选型是 React ,所以一开始还尝试应用 github 上的一些他人配置好的 react-three 这样的,然而如同没有我须要的那种,只好本人手撸。 实现形式其实整体的还是依据 three官网文档 下面的参数进行设置,不多废话间接上代码: 引入组件 import React, { Component, Fragment } from 'react'import * as THREE from 'three'// import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'// import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader'import FileService from '@/services/FileService'import './styles.less'内容渲染 class Online3DView extends Component { constructor(props) { super(props) this.state = { isModel: false, currentName: '暂无名字', clientX: 0, clientY: 0, } this.threeRef = React.createRef() } componentDidMount() { const { height, width, fileId } = this.props let that = this // 加载要渲染的文件的数据流(Blob) FileService.downloadForPreview(fileId) .then((res) => { const url = window.URL.createObjectURL(res) // todo 初始化场景 const scene = new THREE.Scene() // todo 加载相机 const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 80) camera.position.set(1, 25, 25) camera.lookAt(new THREE.Vector3(0, 0, 0)) //todo 加载光线 const ambLight = new THREE.AmbientLight(0x404040, 1) const pointLight = new THREE.PointLight(0x404040, 0.8) const directionalLight = new THREE.DirectionalLight(0xffffff, 1) pointLight.position.set(100, 10, 0) pointLight.receiveShadow = true scene.add(ambLight) scene.add(pointLight) scene.add(directionalLight) //todo renderer const renderer = new THREE.WebGLRenderer({ antialias: true, }) renderer.setSize(width, height - 10) renderer.setClearColor(0xb9d3ff, 1) // 这里应用哪一种loader就要构建相应的loader,我这里应用了glb文件类型,所以加载了这个 let glbLoader = new GLTFLoader() glbLoader.load(url, function (glTF) { glTF.scene.traverse(function (child) { if (glTF.isMesh) { glTF.frustumCulled = false //模型暗影 glTF.castShadow = true //模型自发光 glTF.material.emissive = glTF.material.color glTF.material.emissiveMap = glTF.material.map } }) scene.add(glTF.scene) // todo 场景控制器初始化 const controls = new OrbitControls(camera, renderer.domElement) controls.enabled = true // 鼠标管制是否可用 // 是否主动旋转 controls.autoRotate = true controls.autoRotateSpeed = 0.05 //是否可旋转,旋转速度(鼠标左键) controls.enableRotate = true controls.rotateSpeed = 0.3 //controls.target = new THREE.Vector();//摄像机聚焦到某一个点 //最大最小相机挪动间隔(景深相机) controls.minDistance = 10 controls.maxDistance = 100 //最大仰视角和仰视角 controls.minPolarAngle = Math.PI / 4 // 45度视角 controls.maxPolarAngle = Math.PI / 1 // 75度视角 //惯性滑动,滑动大小默认0.25 controls.enableDamping = true controls.dampingFactor = 0.25 //是否可平移,默认挪动速度为7px controls.enablePan = true controls.panSpeed = 0.5 //controls.screenSpacePanning = true; //滚轮缩放管制 controls.enableZoom = true controls.zoomSpeed = 1.5 //程度方向视角限度 //controls.minAzimuthAngle = -Math.PI/4; //controls.maxAzimuthAngle = Math.PI/4; //todo 绑定到类上 that.scene = scene that.camera = camera that.renderer = renderer that.controls = controls //鼠标移入和移出事件高亮显示选中的模型 that.currentObjectColor = null //移入模型的色彩 that.currentObject = null //鼠标移入的模型 // 初始化场景 // 加载到dom元素上 that.threeRef.current.appendChild(that.renderer.domElement) that.start() that.resizeFunc1() that.resizeFunc2() }) }) .catch((err) => {}) window.addEventListener('resize', this.resizeFunc1, false) window.addEventListener('resize', this.resizeFunc2, false) } componentWillUnmount() { this.stop() this.renderer && this.threeRef.current.removeChild(this.renderer.domElement) window.removeEventListener('resize', this.resizeFunc1, false) window.removeEventListener('resize', this.resizeFunc2, false) } // 初始化 start = () => { if (!this.frameId) { this.frameId = requestAnimationFrame(this.animate) } } // 卸载组件的时候去除 stop = () => { cancelAnimationFrame(this.frameId) } // 更新状态 animate = () => { this.controls.update() this.renderScene() this.frameId = requestAnimationFrame(this.animate) } renderScene = () => { this.renderer.render(this.scene, this.camera) } closeModel = (e) => { e.stopPropagation() if (this.controls && !this.controls.autoRotate) { this.controls.autoRotate = true } this.setState({ isModel: false, }) } resizeFunc1 = () => { this.controls.update() } resizeFunc2 = (e) => { const dom = document.getElementById('test_three') const { offsetWidth, offsetHeight } = dom this.camera.aspect = offsetWidth / offsetHeight this.camera.updateProjectionMatrix() this.renderer.setSize(offsetWidth, offsetHeight) } render() { return ( <Fragment> <div className={this.props.className || 'three-component'} id="test_three" ref={this.threeRef} /> </Fragment> ) }}应用他 ...

June 8, 2022 · 3 min · jiezi

关于react.js:React原理之钩子函数useEffect

React原理之钩子函数useEffect题目内容useEffectuseEffect定义、参数、作用useEffectuseEffect原理useEffectuseEffect实现useEffect定义、参数、作用useEffect原理useEffect实现https://zh-hans.reactjs.org/d...

June 8, 2022 · 1 min · jiezi

关于react.js:使用-ViroReact-开发增强实现应用的一个具体例子

笔者之前的文章 应用 JavaScript 开发AR(加强事实)挪动利用的准备常识和环境搭建,介绍了应用加强事实开发库 ViroReact 进行利用开发所需把握的一些最根底的概念和环境搭建步骤。 本文开始具体介绍应用 ViroReact 进行编码开发的技术细节。 依照本文步骤开发而成的利用成果,能够从上面两个视频 demo 查看: https://v.qq.com/x/page/o3003...https://v.qq.com/x/page/q3003...这个加强事实利用反对实时地更换特斯拉车身的色彩,可能帮忙使用者不便地查看同一型号的特斯拉汽车,在不同车身色彩外观下的不同视觉效果。 ViroReact 的官网有一个步骤十分具体的向导: 一步步照着做,最初就能通过手机摄像头,在实在的场景里能看到一个硬编码的Hello World字符串和一些 3D 物体。 这个 Hello World 级别的源代码在ViroReact官网上能下载,大家能够下载到本地运行,跑通之后,就能持续学习本文余下局部介绍的技术细节了。 关上基于 ViroReact 的 Node.js 我的项目,找到 package.json,项目名称为ViroSample, 外面申明了对React-Native和React-viro的依赖。 React-Native 加 ViroReact这套组合的妙处在于“一次编写,到处运行”的跨平台个性。编写一次JavaScript代码,能在iOS和Android两套操作系统里以原生利用的形式运行。 以Android为例,执行命令行react-native start 加上react-native run-android 后,在android文件夹里能找到针对Android平台生成的原生利用局部源代码。最重要的两个利用引导文件,一个是MainActivity.java, 通过回调函数的形式返回了AR利用的项目名称: MainApplication.java的getJSMainModuleName通过回调函数的形式指明了JavaScript入口模块的名称: 因为本文不是React-Native的解说文章,所以不深刻论述React-Native利用在Android平台的启动原理,感兴趣的敌人能够自行搜寻。React-Native生态圈十分沉闷,相似的原理剖析文章不可胜数。 React-Native + ViroReact开发的加强事实利用,其典型实现套路Jerry归纳起来就三步:Match - Replace - Augment Match - 匹配因为加强事实利用都是将代码生成的虚构物品叠加到事实场景中,因而利用开发人员须要帮忙ViroReact找到事实场景中的一个附丽立体,这样ViroReact能够把这个附丽立体映射到手机的二维屏幕上,接下来 ViroReact 就能在二维屏幕上绘制虚构物体了。 ViroReact提供了一个标签 ViroARImageMarker, 顾名思义,该标签可能容许利用开发人员定义一个“Marker”(标识,标记)。 用编程术语来说,这个标签定义的就是一个place holder,通过target属性,关联一个利用开发人员指定的图片。当用户应用加强事实利用通过摄像头在事实世界扫描到和ViroARImageMarker指定的图片相匹配的图形时,ViroReact就会将Marker指定的图形替换成利用开发人员当时筹备好的3D模型。这个匹配 - 替换过程是ViroReact主动实现的,利用开发人员只须要提供Marker指向的图片和待替换的3D模型即可。采纳这种形式实现的AR利用也称为Marker based AR利用(当然还有不借助Marker实现的AR利用). ...

June 6, 2022 · 1 min · jiezi

关于react.js:最好用的-6-个-React-Tree-select-树形组件测评与推荐

本文完整版:《最好用的 6 个 React Tree select 树形组件测评与举荐》 React 树形选择器(React tree select)组件在搭建 React 的 app 中特地罕用,React tree select 除了简略的树形构造外,还有十分多样的性能来配合不同场景的应用。比方搜寻过滤,前端增加删除树枝,前端编辑批改子树名,拖拽排序,对用户操作事件记录等。本文记录了我本人应用多年最好用的 6 款 React tree select 组件,每一款都通过我理论测试,举荐给大家。 如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 接下来介绍 6 款我本人罕用的 React tree select第三方组件,它们各有特色,心愿能帮你找到适合你的选择器 React Sortable Tree - 全功能,树状单选多选、可拖拽、过滤搜寻、多种主题可选React Treebeard - 纯树形选择器、轻捷趁手、有过滤搜寻性能RC Tree - 资源管理器树状型选择器、可拖拽编辑、动静生成、icon 可换React Animated Tree - 有丑陋的动效的根底款树形选择器,没有多余性能React Dropdown Tree Select - 树形下拉菜单勾选选择器,是树形+checkbox+下拉选择器的合集组件React Checkbox Tree - 带有 checkbox 的树状组件、有过滤搜寻性能1.React Sortable Tree - 全功能,树状单选多选、可拖拽、过滤搜寻、多种主题可选 react-sortable-tree 放在第一个举荐,因为它涵盖了大多数你须要的性能,单选多选,鼠标拖拽子集到新合集,前端含糊搜寻,你须要的性能它全有。 它还有多种主题可供选择,比方,win文件管理器、树状全节点拖动、notion 型的块拖动等主题。 ...

June 6, 2022 · 1 min · jiezi

关于react.js:React-Ant-Design-表单-添加-正则

形容: 给表单 增加 正则<Form.Item label="左侧的 label 信息 写在这里"> {getFieldDecorator('userName', { rules: [ { required: true, pattern: new RegExp(/^(?!(\s+$))^[\w\s]+$/), message: '输出的值不正确的提醒写在这里', }, ], })(<Input placeholder="请输出默认提醒 信息" allowClear />)}</Form.Item>

June 5, 2022 · 1 min · jiezi

关于react.js:reactquery手把手教程①入门reactquery

入门react-query写在后面因为国内较少有比拟零碎的react-query教程,因而笔者联合官网文档以及官网课程的内容,心愿写一个较为全面的教程。本文将以各种例子作为切入点,尽可能通俗易懂地解说相干知识点。如果有谬误,还请大家在评论区指出,笔者会尽快改过。 目录[入门react-query]() 已于2022-06-05更新版本阐明本教程基于react-query@4版本编写,此版本目前(2022-06-05)为alpha版本。 在线演示基于stackblitz 平台 从在react中后端申请数据开始说起在日常的开发中,免不了申请后端接口。在申请接口时,常常会波及到以下解决 加载状态后端返回数据存储如果接口有报错信息,展现报错信息刷新数据等等 上面来看一个满足了上述解决的例子 点我查看例子①在线演示  PS:以下代码将会从github申请一句富裕禅意(逼格高)的话,并显示在页面上例子① import * as React from 'react';export default function App() { // 存储 后端返回数据 const [zen, setZen] = React.useState(''); // 存储 加载状态 const [isLoading, setIsLoading] = React.useState(false); // 存储 是否申请胜利 const [isError, setIsError] = React.useState(false); // 存储 后端返回的谬误数据 const [errorMessage, setErrorMessage] = React.useState(''); const fetchData = () => { // 开始获取数据,将isLoading置为true setIsLoading(true); fetch('https://api.github.com/zen') .then(async (response) => { // 如果申请返回status不为200 则抛出后端谬误 if (response.status !== 200) { const { message } = await response.json(); throw new Error(message); } return response.text(); }) .then((text: string) => { // 申请实现将isLoading置为false setIsLoading(false); // 接口申请胜利,将isError置为false setIsError(false); // 存储后端返回的数据 setZen(text); }) .catch((error) => { // 申请实现将isLoading置为false setIsLoading(false); // 接口申请谬误,将isError置为true setIsError(true); // 存储后端返回的谬误数据 setErrorMessage(error.message); }); }; React.useEffect(() => { // 初始化申请数据 fetchData(); }, []); return ( <div> <h1>Zen from Github</h1> <p>{isLoading ? '加载中...' : isError ? errorMessage : zen}</p> {!isLoading && ( <button onClick={fetchData}>{isError ? '重试' : '刷新'}</button> )} </div> );}在下面的例子中 ...

June 5, 2022 · 3 min · jiezi

关于react.js:5款-React-实时消息提示通知MessageNotification组件推荐与测评

本文完整版:《5款 React 实时音讯提醒告诉(Message/Notification)组件举荐与测评》 React 音讯提醒告诉组件(Message / Notification)是咱们日常开发中常常应用的组件,它可用作与用户交互的反馈提醒,信息提交胜利、谬误、操作正告等场景应用。原生JavaScript 提供了alert、prompt、confirm 等办法,这三个办法的不反对定制化,应用场景重大受限,特地是 alert 在浏览器外弹窗,体验十分蹩脚。因而要想给用户提供良好的应用体验,咱们须要封装一个定制化较好的 React 音讯提醒组件,这种组件看似简略,但也存在十分多深坑要小心,例如遮罩层、隐没工夫、点击事件的冒泡解决等。 我本人在开发和钻研 Message / Notification 性能组件时,发现其实 Github 上有十分多制作精良,应用场景定位清晰的第三方音讯提醒组件库可用,社区成熟,代码简洁,间接援用即可,齐全没必要本人写,本文给大家举荐 5 款我用过的开源音讯提醒库,各有劣势,可按需自取。 如果你正在搭建后盾管理工具,又不想解决前端问题,举荐应用卡拉云 ,卡拉云是新一代低代码开发工具,可一键接入常见数据库及 API ,无需懂前端,仅需拖拽即可疾速搭建属于你本人的后盾管理工具,一周工作量缩减至一天,详见本文文末。 接下来我来介绍一下我用过且感觉不错的 5 款常见的 React Message / Notification 组件,大家可依据本人实现需求自取。 React Toastify - 专一实时音讯提醒 各类款式随便批改 你想要的它都有React Hot Toast - 动效丰盛、代码简洁、款式自定义、轻量级音讯提醒组件Notistack - 轻量级,适宜根底提醒的利用场景React Notification System - 带有按钮的音讯弹窗组件,给用户更多交互Reapop - UI丑陋、多种可定义款式、动效丰盛、轻量级React Toastify - 专一实时音讯提醒 各类款式随便批改 你想要的它都有 react-toastify 是简洁高效的音讯提醒组件库,惯例的胜利、谬误、正告款式随便筛选。配置简略,几秒钟就能实现你须要的提醒音讯款式,更不用说惯例的色彩、字体、字号、弹出地位等细节,更是随便批改。 傻瓜式配置,10秒钟实现所有设置工作可定制开发,简略便捷可敞开滑动动画成果可在提示框中嵌入 React 组件可定义每个 toast 行为有进度条显示白天夜间模式主动切换扩大浏览:《7 款顶级好用的 React 挪动端 ui 组件库测评举荐》 ...

June 4, 2022 · 1 min · jiezi

关于react.js:模拟DataV实现

模仿DataV实现仓库地址: https://github.com/JackDan9/j...

June 1, 2022 · 1 min · jiezi

关于react.js:顶级好用的-React-表单设计生成器可拖拽生成表单

本文完整版:《顶级好用的 React 表单设计生成器,可拖拽生成表单》 React 前端开发中,表单组件是排在前三的高频应用的组件,如何疾速构建表单,节俭力量,防止反复造轮子呢,抉择一款适宜本人的前端表单设计生成器就十分重要了。本文介绍 3 款顶级好用的 React 表单设计器,其中最初一款卡拉云,是新一代低代码开发工具,不仅能主动生成各类表单,还能够拖拽生成其余常见的前端组件,一行代码连贯前后端数据,可疾速接入数据库/api。它是表单设计器的超集,可间接生成属于你的后盾管理工具,无敌好用。 本文介绍 3 款各有特点的表单设计器 Formily designable 表单设计生成器 - 拖拽生成 React 表单代码,反对移 动端表单设计form-render - 阿里团队开源表单设计器,自家 Antd UI 框架敌对卡拉云 - 低代码开发工具,表单设计器的超集,拖拽表单间接连贯后端数据,即搭即用Formily designable 表单设计生成器 - 拖拽生成 React 表单代码,反对挪动端表单设计 Github:https://github.com/alibaba/designable designable 是阿里旗下 Formily 表单解决方案的在线可视化表单设计生成器,可在线拖拽生成组件间接用于 React 框架的我的项目中。反对 PC 端和挪动端设计,一键生成 React 代码或 JSON 表单代码。 Formily designable 性能特点 可公有部署,可内置在我的项目中,在线可视化表单生成器一键生成 React 表单组件代码可内置在我的项目里,用户可在你的工具后盾应用此组件生成表单有表单验证性能官网文档清晰详实扩大浏览:《7 款顶级好用的 React 挪动端 ui 组件库测评举荐》 form-render - 阿里团队开源表单设计器,自家 Antd UI 框架敌对 Github:https://github.com/alibaba/x-render FormRender 是阿里旗下的飞猪 app 的表单生成计划,从 2017 年在外部开始应用到 2019 年正式对外开源,FormRender 经验了多个阿里大我的项目的迭代和降级,细节曾经相当全面。 ...

June 1, 2022 · 1 min · jiezi