关于react.js:2021前端react面试题汇总

2021前端react面试题汇总React视频教程系列React 实战:CNode视频教程残缺教程目录:点击查看 React经典教程-从入门到精通残缺教程目录:点击查看 最新最全前端毕设我的项目(小程序+VUE+Noed+React+uni app+Express+Mongodb)残缺教程目录:点击查看 2021前端React精品教程残缺教程目录:点击查看 1. mobox 和 redux 有什么区别?(1)共同点 为了解决状态管理混乱,无奈无效同步的问题对立保护治理利用状态;某一状态只有一个可信数据起源(通常命名为store,指状态容器);操作更新状态形式对立,并且可控(通常以action形式提供更新状态的路径);反对将store与React组件连贯,如react-redux,mobx- react;(2)区别 Redux更多的是遵循Flux模式的一种实现,是一个 JavaScript库,它关注点次要是以下几方面∶ Action∶ 一个JavaScript对象,形容动作相干信息,次要蕴含type属性和payload属性∶ o type∶ action 类型; o payload∶ 负载数据;复制代码Reducer∶ 定义利用状态如何响应不同动作(action),如何更新状态;Store∶ 治理action和reducer及其关系的对象,次要提供以下性能∶ o 保护利用状态并反对拜访状态(getState());o 反对监听action的散发,更新状态(dispatch(action)); o 反对订阅store的变更(subscribe(listener));复制代码异步流∶ 因为Redux所有对store状态的变更,都应该通过action触发,异步工作(通常都是业务或获取数据工作)也不例外,而为了不将业务或数据相干的工作混入React组件中,就须要应用其余框架配合治理异步工作流程,如redux-thunk,redux-saga等;Mobx是一个通明函数响应式编程的状态治理库,它使得状态治理简略可伸缩∶ Action∶定义扭转状态的动作函数,包含如何变更状态;Store∶ 集中管理模块状态(State)和动作(action)Derivation(衍生)∶ 从利用状态中派生而出,且没有任何其余影响的数据比照总结: redux将数据保留在繁多的store中,mobx将数据保留在扩散的多个store中redux应用plain object保留数据,须要手动解决变动后的操作;mobx实用observable保留数据,数据变动后主动解决响应的操作redux应用不可变状态,这意味着状态是只读的,不能间接去批改它,而是应该返回一个新的状态,同时应用纯函数;mobx中的状态是可变的,能够间接对其进行批改mobx相对来说比较简单,在其中有很多的形象,mobx更多的应用面向对象的编程思维;redux会比较复杂,因为其中的函数式编程思维把握起来不是那么容易,同时须要借助一系列的中间件来解决异步和副作用mobx中有更多的形象和封装,调试会比拟艰难,同时后果也难以预测;而redux提供可能进行工夫回溯的开发工具,同时其纯函数以及更少的形象,让调试变得更加的容易2. Redux 和 Vuex 有什么区别,它们的独特思维(1)Redux 和 Vuex区别 Vuex改良了Redux中的Action和Reducer函数,以mutations变动函数取代Reducer,无需switch,只需在对应的mutation函数里扭转state值即可Vuex因为Vue主动从新渲染的个性,无需订阅从新渲染函数,只有生成新的State即可Vuex数据流的程序是∶View调用store.commit提交对应的申请到Store中对应的mutation函数->store扭转(vue检测到数据变动主动渲染)艰深点了解就是,vuex 弱化 dispatch,通过commit进行 store状态的一次更变;勾销了action概念,不用传入特定的 action模式进行指定变更;弱化reducer,基于commit参数间接对数据进行转变,使得框架更加繁难; (2)独特思维 单—的数据源变动能够预测实质上∶ redux与vuex都是对mvvm思维的服务,将数据从视图中抽离的一种计划。 3. Redux 中间件是怎么拿到store 和 action? 而后怎么解决?redux中间件实质就是一个函数柯里化。redux applyMiddleware Api 源码中每个middleware 承受2个参数, Store 的getState 函数和dispatch 函数,别离取得store和action,最终返回一个函数。该函数会被传入 next 的下一个 middleware 的 dispatch 办法,并返回一个接管 action 的新函数,这个函数能够间接调用 next(action),或者在其余须要的时刻调用,甚至基本不去调用它。调用链中最初一个 middleware 会承受实在的 store的 dispatch 办法作为 next 参数,并借此完结调用链。所以,middleware 的函数签名是({ getState,dispatch })=> next => action。 ...

September 24, 2021 · 3 min · jiezi

关于react.js:HOC-vs-Render-Props-vs-Hooks

残缺高频题库仓库地址:https://github.com/hzfe/aweso... 残缺高频题库浏览地址:https://febook.hzfe.org/ 相干问题什么是 HOC / Render Props / Hooks为什么须要 HOC / Render Props / Hooks如何进步代码复用性Hooks 的实现原理Hooks 相比其余计划有什么劣势答复关键点复用性 HOC / Render Props / Hooks 三种写法都能够进步代码的复用性,但实现办法不同:HOC 是对传入的组件进行加强后,返回新的组件给开发者;Render Props 是指将一个返回 React 组件的函数,作为 prop 传给另一个 React 组件的共享代码的技术;Hooks 是 React 提供的一组 API,使开发者能够在不编写 class 的状况下应用 state 和其余 React 个性。 知识点深刻1. HOC (Higher Order Component,即高阶组件)HOC 是 React 中复用代码的编程模式。具体来说,高阶组件是一个纯函数,它接管一个组件并返回一个新的组件。常见例子:React Redux 的 connect,将 Redux Store 和 React 组件分割起来。 // react-redux connect 例子const ConnectedMyComponent = connect(mapState)(MyComponent);``````// 实现一个简略的 HOC 例子function logProps(WrappedComponent) {  return class extends React.Component {    componentDidUpdate(prevProps) {      console.log("Current props: ", this.props);      console.log("Previous props: ", prevProps);    }    render() {      return <WrappedComponent {...this.props} />;    }  };}2. Render PropsRender Props 是 React 中复用代码的编程模式。次要解决组件逻辑雷同而渲染规定不同的复用问题。常见例子:React Router 中,自定义 render 函数,按需应用 routeProps 来渲染业务组件。 ...

September 23, 2021 · 1 min · jiezi

关于react.js:使用monacoeditorregisterCompletionItemProvider多次注册最终导致展示的提示内容重复

最近我的项目实现一个提醒性能,输出某个符号,展现匹配的内容,和代码提醒性能相似。最终抉择了monaco-editor,微软开发的js库,vscode也是基于这个库开发的。 在开发过程中,遇到些问题,因为文档不是很敌对,花了半天才解决问题。上面次要记录一下问题以及解决办法,心愿当前遇到这些问题的童鞋能疾速避坑。遇到的问题以及解决办法问题:在Antd Modal中应用monaco-editor,显示Modal后敞开Modal,再次关上Modal,monaco-editor的提醒内容就会反复,显示几次Modal,对应的内容就会反复几次,如下图: 解决办法思路1:通过调试发现,registerCompletionItemProvider办法屡次执行,首先猜到的可能是插件屡次创立,没有销毁造成的,查阅对应的文档后,发现有插件提供了一个销毁的办法: monaco.editor.dispose()于是,尝试在组件销毁之前调用下面的办法,然而运行后发现并不失效,上述问题仍旧存在,此法不通~ 思路2:既然registerCompletionItemProvider屡次执行,那么给组件中增加一个全局的计数器count,组件注册一次后执行一次count+1,只有当count===0时,才走对应的插件注册逻辑,否则间接取缓存的数据。局部代码片段如下: let count = 0; monaco.languages.registerCompletionItemProvider(languageName, { triggerCharacters: ['['], provideCompletionItems: function (model, position, context) { count=count+1; if(count===1){ let suggestions = []; if (context.triggerCharacter === '[') { [...dimensions, ...modules].forEach((item, index) => { suggestions.push({ label: item.customName, insertText: `${item.customName}]`, kind: 12, }); }); } return { suggestions }; } }, });这种形式简略粗犷,如果须要插件提醒的内容是固定的,间接用缓存的数据是能够解决这个问题。然而!!!我遇到的需要是,提醒的内容是依据接口动静取的。所以,此法仍旧不通~ 思路3:因为谷歌和百度都没用找到称心的答案,于是去monaco-editor的GitHub 的 issues中查找答案,刚开始依据registerCompletionItemProvider关键字搜寻,然而并没有相似的问题,而后又尝试搜寻provideCompletionItems关键词,最终在issues中找到了2个相似的问题,链接如下: https://github.com/microsoft/monaco-editor/issues/2217 https://github.com/microsoft/monaco-editor/issues/2084 最终解决办法:在registerCompletionItemProvider注册创立时,将创立的对象存储起来,如下: monacoProviderRef.current = monaco.languages.registerCompletionItemProvider(languageName, {在组件销毁时,将editor和registerCompletionItemProvider生成的对象一起销毁。代码如下: useEffect(() => { // todo // xxxxxx return () => { // 销毁 monacoProviderRef.current?.dispose(); monacoRef.current?.dispose(); }; }, []);最初测试,bug完满解决! ...

September 20, 2021 · 1 min · jiezi

关于react.js:useEffect和useLayoutEffect的区别

useEffect和useLayoutEffect区别布局副作用useEffect在浏览器渲染实现后执行useLayoutEffect在浏览器渲染前执行特点:useLayoutEffect总是比useEffect先执行useLayoutEffect外面的工作最好影响了Layout(布局)**留神:为了用户体验最好优先应用useEffect**useEffect(副作用)基本上90%的状况下,都应该用这个,这个是在render完结后,你的callback函数执行,然而不会block browser painting,算是某种异步的形式吧,然而class的componentDidMount 和componentDidUpdate是同步的,在render完结后就运行,useEffect在大部分场景下都比class的形式性能更好. useLayoutEffect(布局副作用)这个是用在解决DOM的时候,当你的useEffect外面的操作须要解决DOM,并且会扭转页面的款式,就须要用这个,否则可能会呈现呈现闪屏问题, useLayoutEffect外面的callback函数会在DOM更新实现后立刻执行,然而会在浏览器进行任何绘制之前运行实现,阻塞了浏览器的绘制. 可能讲的不是很分明,看个例子吧 import React, { useEffect, useLayoutEffect, useRef } from "react";import TweenMax from "gsap/TweenMax";import './index.less';const Animate = () => { const REl = useRef(null); useEffect(() => { /*上面这段代码的意思是当组件加载实现后,在0秒的工夫内,将方块的横坐标地位移到600px的地位*/ TweenMax.to(REl.current, 0, {x: 600}) }, []); return ( <div className='animate'> <div ref={REl} className="square">square</div> </div> );};export default Animate;能够分明的看到有一个一闪而过的方块. 改成useLayoutEffect试试: 能够看出,每次刷新,页面根本没变动!

September 18, 2021 · 1 min · jiezi

关于react.js:2021高频前端面试题汇总之React篇

2021高频前端面试题汇总之React篇React视频教程系列React 实战:CNode视频教程残缺教程目录:点击查看 1. React 事件机制<div onClick={this.handleClick.bind(this)}>点我</div>复制代码React并不是将click事件绑定到了div的实在DOM上,而是在document处监听了所有的事件,当事件产生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的形式不仅仅缩小了内存的耗费,还能在组件挂在销毁时对立订阅和移除事件。 除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react本人实现的合成事件(SyntheticEvent)。因而如果不想要是事件冒泡的话应该调用event.preventDefault()办法,而不是调用event.stopProppagation()办法。 JSX 上写的事件并没有绑定在对应的实在 DOM 上,而是通过事件代理的形式,将所有的事件都对立绑定在了 document 上。这样的形式不仅缩小了内存耗费,还能在组件挂载销毁时对立订阅和移除事件。 另外冒泡到 document 上的事件也不是原生浏览器事件,而是 React 本人实现的合成事件(SyntheticEvent)。因而咱们如果不想要事件冒泡的话,调用 event.stopPropagation 是有效的,而应该调用 event.preventDefault。 实现合成事件的目标如下: 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;对于原生浏览器事件来说,浏览器会给监听器创立一个事件对象。如果你有很多的事件监听,那么就须要调配很多的事件对象,造成高额的内存调配问题。然而对于合成事件来说,有一个事件池专门来治理它们的创立和销毁,当事件须要被应用时,就会从池子中复用对象,事件回调完结后,就会销毁事件对象上的属性,从而便于下次复用事件对象。2. React 高阶组件、Render props、hooks 有什么区别,为什么要一直迭代这三者是目前react解决代码复用的次要形式: 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。具体而言,高阶组件是参数为组件,返回值为新组件的函数。render props是指一种在 React 组件之间应用一个值为函数的 prop 共享代码的简略技术,更具体的说,render prop 是一个用于告知组件须要渲染什么内容的函数 prop。通常,render props 和高阶组件只渲染一个子节点。让 Hook 来服务这个应用场景更加简略。这两种模式仍有用武之地,(例如,一个虚构滚动条组件或者会有一个 renderltem 属性,或是一个可见的容器组件或者会有它本人的 DOM 构造)。但在大部分场景下,Hook 足够了,并且可能帮忙缩小嵌套。(1)HOC 官网解释∶ 高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。简言之,HOC是一种组件的设计模式,HOC承受一个组件和额定的参数(如果须要),返回一个新的组件。HOC 是纯函数,没有副作用。 // hoc的定义function withSubscription(WrappedComponent, selectData) { return class extends React.Component { constructor(props) { super(props); this.state = { data: selectData(DataSource, props) }; } // 一些通用的逻辑解决 render() { // ... 并应用新数据渲染被包装的组件! return <WrappedComponent data={this.state.data} {...this.props} />; } };// 应用const BlogPostWithSubscription = withSubscription(BlogPost, (DataSource, props) => DataSource.getBlogPost(props.id));复制代码HOC的优缺点∶ ...

September 15, 2021 · 3 min · jiezi

关于react.js:react配置路由

1.开发环境 react2.电脑系统 windows10专业版3.在应用react开发的过程中,咱们发现react官网没有路由,而后去网上搜寻,给出了两个罕用的react-router和react-router-dom,上面我来分享一下。4.react-router和react-router-dom有什么区别? 置信很多小伙伴们刚开始的都会和我一样,在应用react来创立路由的时候,写的是:import *** from 'react-router';而后百度了很多博客,发现是:import *** from 'react-router-dom';4-1.那么react-router和react-router-dom有什么关系呢? react-router:提供了router的外围api,如Router/Route/Switch等,但没有提供无关dom操作进行路由跳转api;react-router-dom:提供了BrowserRouter/Route/Link等api,能够通过dom操作触发事件管制路由那么咱们要怎么用呢?首先,react-router-dom里蕴含了react-router的依赖,因而咱们在装置的时候只须要装置后者即可。npm i react-router-dom -S4-2.根底应用 //引入react jsx写法的必须import React from 'react'; //引入须要用到的页面组件 import Home from './pages/home';import About from './pages/about';//引入一些模块import { BrowserRouter as Router, Route} from "react-router-dom";function router(){return (<Router> <Route path="/home" component={Home} /> <Route path="/about" component={About} /></Router>);}export default router;//home.jsimport React, { Component } from 'react';export default class Home extends Component { render() { return (<h1> 欢送,这里是Home </h1>) }}//about.jsimport React, { Component } from 'react';export default class About extends Component { render() { return (<h1> 欢送,这里是About </h1>) }}//在app.js中引入import Router from './Router'class App extends React.Component {render(){return ( <Router />);}}5.重定向 ...

September 15, 2021 · 1 min · jiezi

关于react.js:前端两大框架React与Vue对比总结

React和Vue是目前前端最支流的两大框架,最近面试总是被问及React和Vue的异同比照,这次就大略梳理一下。 GitHub上star比照截图 设计思维React官网介绍React是一个用于构建用户界面的 JavaScript 库。React举荐JSX + inline style, 也就是把HTML和CSS全都写进JavaScript了,即 ”all in js“,HTML和css都能够放到js中。React主张函数编程,举荐应用纯函数,数据不可变,单向数据流,然而能够手动编写onChange等事件处理函数实现双向数据流。联合JSX轻松实现渲染模板 Vue官网介绍Vue是一套用于构建用户界面的渐进式框架,与其它大型框架不同的是,Vue 被设计为能够自底向上逐层利用。Vue保留了html、css、js拆散的写法,使得现有的前端开发者在开发的时候能放弃原有的习惯,更靠近罕用的web开发方式,模板就是一般的html,数据绑定应用mustache格调,款式间接应用css。Vue认为数据是可变的,应用v-model实现双向数据流。 构建与调试* 构建工具React创立新的单页利用的最佳形式: Create React App npx create-react-app my-appcd my-appnpm startVue官网构建工具: vue-cli npm install -g @vue/clivue create my-appnpm run serve# ORyarn global add @vue/clivue create my-appnpm run serve* 调试React Developer Tools用来调试reactRedux DevTools用来调试reduxVue.js devtools用来调试vue,vuex等 JSX vs 模板React没有模板,是通过类组件的render办法的返回值或者函数式组件的返回值来渲染虚构DOM,通过原生js来实现条件渲染、循环渲染、插值等。也能够应用JSX语法糖来更简略地去形容树状构造;Vue则是应用模板,模板更贴近HTML与js代码、css代码分来到,应用mustache进行数据绑定,应用指令来实现条件渲染、循环渲染等 数据变动监听* 数据流比照React是单向数据流,且是不容许子组件批改父组件传来的props,组件的state是容许批改的,能够通过setState(异步的)来进行更改,不容许通过this.state这种形式间接更改组件的状态。vue2.x中也不容许子组件批改父组件传递的props,组件与DOM之间能够通过v-model双向绑定 * 监听数据变动形式比照React组件在调用setState后,默认状况下因为shouldComponentUpdate()里的返回值是true所以全副组件都会从新渲染,造成很多不必要的渲染,能够通过在组件的shouldComponentUpdate()生命周期办法中来进行渲染优化或者间接应用官网的PureComponent(shouldComponentUpdate()中进行状态和属性的浅比拟来决定是否须要渲染)Vue2.x中通过Object.defineProperty()把data对象中所有属性增加到vm上。为每一个增加到vm上的属性,都指定一个getter/setter。在getter/setter外部去操作(读/写)data中对应的属性。Vue3中通过new Proxy()和Reflect来为数据指定一个getter/setter。当设置数据的时候会触发对应的setter办法,从而进一步触发vm的watcher办法,而后数据更改,vm则会进一步触发视图更新操作。vue可能更加准确的晓得数据变动,只从新渲染与变动数据绑定的DOM 事件React通过属性来绑定事件,React类组件须要本人手动处理事件this指向的问题 class Demo extends React.Component{ /* 通过onXxx属性指定事件处理函数(留神大小写) a.React应用的是自定义(合成)事件, 而不是应用的原生DOM事件 —————— 为了更好的兼容性 b.React中的事件是通过事件委托形式解决的(委托给组件最外层的元素) ————————为了的高效 */ constructor(props){ super(props); //初始化状态 this.state = { number: 22 } //解决this指向问题 this.showInfo3 = this.showInfo3.bind(this) } showInfo1 = ()=> { console.log(this.state); } showInfo2 = (e, number)=> { console.log(number); console.log(this.state); } showInfo3() { console.log(this.state); } showInfo4(number) { return (e) => { console.log(number); console.log(this.state); } } render(){ return( <div> <button onClick={this.showInfo1}>点我提示信息(不传参)</button> <button onClick={this.showInfo3}>点我提示信息(不传参)</button> <button onClick={(e) => {this.showInfo2(e,66)}}>点我提示信息(传参)</button> <button onClick={this.showInfo4(88)}>点我提示信息(传参)</button> </div> ) } }Vue中的事件处理函数都放到methods配置对象中,并把methods中的每一个事件处理函数都放到vm身上并把函数的this绑定到vm身上,通过指令来实现事件绑定 ...

September 13, 2021 · 1 min · jiezi

关于react.js:React17-系统精讲-结合TS打造旅游电商平台

引入原则: <head> </script> </script> </script></head> body区域 <div id='example'></div><script type='text/bable'> //**our codes goes here!</script> 实际上线用babel进行转换 bable src --out-dir build ReactDOM.render() 示例: ReactDOM.render( <h1>hello world!</h1>, document.getElementById('example');) JSX语法 var names =['Alice','Emily','Kate'];ReactDOM.render( <div> { names.map(function(name){ return <div>Hello,{name}!</div>})} </div>, document.getElementById('example')); JSX容许在模板中直接插入JavaScript变量 var arr = [ <h1>Hello world!</h1>, <h2>React is awesome</h2> ];ReactDOM.render( <div>{arr}</div>, document.getElementById('example')); 组件 React.createClass用于生成一个组件类 var HelloMessage = React.creatClass({ render:function(){return <h1>Hello {this.props.name}</h1>;}});ReactDOM.render( <HelloMessage name='john' />, document.getElementById('example')); 组件的第一个字母必须大写 组件只能蕴含一个顶层标签 class属性需要写成className this.props.children this.props.children 示意组件所有的子节点 var NoteList = React.createClass({ render:function(){ ...

September 10, 2021 · 2 min · jiezi

关于react.js:react面试题

一、React组件生命周期有几个阶段初始渲染阶段:这是组件行将开始其生命之旅并进入 DOM 的阶段。 getDefaultProps:获取实例的默认属性getInitialState:获取每个实例的初始化状态componentWillMount:组件行将被装载、渲染到页面上render:组件在这里生成虚构的 DOM 节点componentDidMount:组件真正在被装载之后 更新阶段:一旦组件被增加到 DOM,它只有在 prop 或状态发生变化时才可能更新和从新渲染。这些只产生在这个阶段。 componentWillReceiveProps:组件将要接管到属性的时候调用shouldComponentUpdate:组件承受到新属性或者新状态的时候(能够返回 false,接收数据后不更新,阻止 render 调用,前面的函数不会被继续执行了)componentWillUpdate:组件行将更新不能批改属性和状态render:组件从新描述componentDidUpdate:组件曾经更新 卸载阶段:这是组件生命周期的最初阶段,组件被销毁并从 DOM 中删除。 componentWillUnmount:组件行将销毁二、React 组件的生命周期办法componentWillMount() – 在渲染之前执行,在客户端和服务器端都会执行。componentDidMount() – 仅在第一次渲染后在客户端执行。componentWillReceiveProps() – 当从父类接管到 props 并且在调用另一个渲染器之前调用。shouldComponentUpdate() – 依据特定条件返回 true 或 false。如果你心愿更新组件,请返回true 否则返回 false。默认状况下,它返回 false。componentWillUpdate() – 在 DOM 中进行渲染之前调用。componentDidUpdate() – 在渲染产生后立刻调用。componentWillUnmount() – 从 DOM 卸载组件后调用。用于清理内存空间。三、受控组件和非受控组件的区别受控组件是React管制的组件,input等表单输入框值不存在于 DOM 中,而是以咱们的组件状态存在。每当咱们想要更新值时,咱们就像以前一样调用setState。不受管制组件是您的表单数据由 DOM 解决,而不是React 组件,Refs 用于获取其以后值;四、React组件事件代理的原理 和原生HTML定义事件的惟一区别就是JSX采纳驼峰写法来形容事件名称,大括号中依然是规范的JavaScript表达式,返回一个事件处理函数。在JSX中你不须要关怀什么机会去移除事件绑定,因为React会在对应的实在DOM节点移除时就主动解除了事件绑定。 React并不会真正的绑定事件到每一个具体的元素上,而是采纳事件代理的模式:在根节点document上为每种事件增加惟一的Listener,而后通过事件的target找到实在的触发元素。这样从触发元素到顶层节点之间的所有节点如果有绑定这个事件,React都会触发对应的事件处理函数。这就是所谓的React模仿事件零碎。五、为什么虚构 dom 会进步性能虚构dom(virtual dom) 是 JS对象,是一个实在dom的JS对象;虚构 dom 相当于在 js 和实在 dom 两头加了一个缓存,利用 dom diff 算法防止了没有必要的 dom 操作,从而进步性能。 ...

September 8, 2021 · 1 min · jiezi

关于react.js:React-Native重大架构升级即将发布

一、前言7 月 14 日,React Native 外围团队的 Joshua Gross 在 Twitter 说,RN 的新架构曾经在 Facebook 外部落地了,并且99%的代码曾经开源。其实,早在 2018 年 6 月,Facebook 官网就发表了大规模重构 React Native 的打算及重构路线图,目标是为了让 React Native 更加轻量化、更适应混合开发,靠近甚至达到原生的体验。 这次的架构降级对于 React Native 意义重大,依照官网的说法,降级后的RN性能将失去大幅晋升,次要是解决诟病已久的性能问题,下图是React Native的一个版本公布阐明。 为了让 RN 更轻量化、更适应混合开发,靠近甚至达到原生的体验,React Native的优化措施包含以下几个方面: 扭转线程模型,UI 更新不再同时须要在三个不同的线程上触发执行,而是能够在任意线程上同步调用 JavaScript 进行优先更新,同时将低优先级工作推出主线程,以便放弃对 UI 的响应。引入异步渲染能力,容许多个渲染并简化异步数据处理。简化了 JSBridge的渲染逻辑,优化了底层渲染架构,让它更快更轻量。二、新老架构比照对于有过RN开发教训的都晓得,原有RN架构 JS 层与 Native 的通信过多的依赖 Bridge,而且是异步通信,这就造成一些通信频率较高的交互和设计就很难实现,同时也影响页面的渲染。而新架构也正是从这一点登程,对 Bridge 这层做了大量的革新,使得 UI 和 API 的调用,从原有异步形式调整到能够同步或者异步与 Native 通信,解决了频繁通信的瓶颈问题。 同时,新架构应用JSI(全称是 JavaScript Interface)代替原来的 Bridge, JS层间接调用 C++层进而调用 Java/OC 的形式,实现 JS 和 Java/OC 之间的互相操作,大大提高了通信的效率。得益于JSI的全新架构,JavaScript 能够间接调用 Native 模块的办法。 ...

September 4, 2021 · 3 min · jiezi

关于react.js:antd-select联动数据处理

需要: 抉择大厦,把抉择完大厦id传给楼层下拉列表,抉择大厦申请楼层列表,相互可搜寻大厦没有配置楼层时,做校验问题 新增编辑时只传抉择完的楼层id,编辑回显后盾给2个id,select封装成form表单子组件应用问题。解决form表单父组件 if (key === "floor_ids") { return ( <Form.Item label="所在地区" className="panel-li-title"> {getFieldDecorator(`floor_ids`, { //无用值 为了展现数据 initialValue: {}, rules: [ { required: true, message: "", }, ], })( // 所在地区大厦和楼层的组件 <FloorSelect2 form={form} // 编辑的时候 拿到了data中 后盾返回大厦和楼层的id 传给子组件 data={data} ></FloorSelect2> )} </Form.Item> );} select子组件1.初始化定义两个数组,buildList大厦列表 floorList楼层列表 state = { // 所在地区逻辑批改buildList: [], //大厦列表floorList: [], //楼层列表};2.定义个申请大厦列表的函数 // 这是楼层的change办法componentDidMount() { this.init(); }init = () => {//获取大厦列表FloorguideAction.floorGuideMeetingBuildList({}).then((results) => { console.log(results); let { data = [] } = results; if (!results.success) { message.error("接口谬误", 0.5); return; } this.setState({ buildList: data, });});};render中遍历buildList数据渲染到大厦下拉框中 ...

September 2, 2021 · 2 min · jiezi

关于react.js:react-报错

问题:无奈对未装置的组件执行React状态更新。这是一个no-op,但它示意应用程序中存在内存透露。要修复此问题,请勾销componentWillUnmount办法中的所有订阅和异步工作。 解决办法 componentWillUnmount() { this.setState = () => { return; }; }

September 2, 2021 · 1 min · jiezi

关于react.js:reactcropper结合Antd-Upload实现图片裁剪并上传

cropper文档cropperjs react-cropper cropperjs翻译文档:cropper.js 裁剪图片并上传(文档翻译+demo) installyarn add react-cropperimport Cropper from 'react-cropper'import 'cropperjs/dist/cropper.css'次要配置阐明viewMode 配置视图模式https://github.com/fengyuanch... 0:无限度1:限度裁剪框不能超出图片的范畴2:限度裁剪框不能超出图片的范畴,且图片填充模式为最长边填充3:限度裁剪框不能超出图片的范畴,且图片填充模式为最短边填充dragMode 配置拖拽模式https://github.com/fengyuanch... crop:拖拽造成新的裁剪框move:拖拽只能挪动图片none:不做解决次要办法阐明onInitialized 获取cropper实例https://github.com/react-crop... onInitialized={(instance) => {cropper.current = instance}}zoom 缩放事件https://github.com/fengyuanch... 在zoom监听事件中限度最大最小缩放比例: const zoom = (e) => { const { ratio, oldRatio } = e.detail // zoom in if (ratio > oldRatio) { if (ratio > maxRatio) { e.preventDefault() cropper.current.zoomTo(maxRatio) } // zoom out } else if (ratio < oldRatio) { if (ratio < minRatio) { e.preventDefault() cropper.current.zoomTo(minRatio) } }}getCanvasData 获取裁剪的图片数据https://github.com/fengyuanch... ...

September 2, 2021 · 1 min · jiezi

关于react.js:react项目中使用svgspriteloader按需加载svg

svg组件 import React, { useRef, useMemo, useState, useEffect } from 'react'import '@/styles/components/svg/index.scoped.scss'type IImport = { default?: Record<string, any> [key: string]: any}type ISvg = { iconClass: string className?: string width?: number height?: number color?: string style?: Record<string, any> onClick?: () => void}const SvgIcon: React.FC<ISvg> = (props: any) => { const { iconClass, className, width = 16, height = 16, color = '#000', style = {}, onClick, } = props const [svgModule, setSvgModule] = useState<IImport>() const getSvg = async () => { const svg = await import(`../../icons/svg/${props.iconClass}.svg`) setSvgModule(svg) } const iconPath = useMemo(() => { if (svgModule && svgModule.default) { return `#${svgModule.default.id}` } }, [iconClass, svgModule]) const Style = { ...style, width: `${width}px`, height: `${height}px`, color, } useEffect(() => { getSvg() }, []) return ( <svg onClick={onClick} style={Style} className={`svg-icon ${className}`} aria-hidden="true" > <use xlinkHref={iconPath} /> </svg> )}export default SvgIconwebpack配置--loader ...

August 31, 2021 · 1 min · jiezi

关于react.js:React-Fiber-原理介绍

一、前言在 React Fiber 架构面世一年多后,最近 React 又公布了最新版 16.8.0,又一激动人心的个性:React Hooks 正式上线,让我降级 React 的志愿越来越强烈了。在降级之前,无妨回到原点,理解下人才济济的 React 团队为什么要大费周章,重写 React 架构,而 Fiber 又是个什么概念。 二、React 15 的问题在页面元素很多,且须要频繁刷新的场景下,React 15 会呈现掉帧的景象。请看以下例子:https://claudiopro.github.io/... 其根本原因,是大量的同步计算工作阻塞了浏览器的 UI 渲染。默认状况下,JS 运算、页面布局和页面绘制都是运行在浏览器的主线程当中,他们之间是互斥的关系。如果 JS 运算继续占用主线程,页面就没法失去及时的更新。当咱们调用setState更新页面的时候,React 会遍历利用的所有节点,计算出差别,而后再更新 UI。整个过程是零打碎敲,不能被打断的。如果页面元素很多,整个过程占用的机会就可能超过 16 毫秒,就容易呈现掉帧的景象。 针对这一问题,React 团队从框架层面对 web 页面的运行机制做了优化,失去很好的成果。 三、解题思路解决主线程长时间被 JS 运算占用这一问题的基本思路,是将运算切割为多个步骤,分批实现。也就是说在实现一部分工作之后,将控制权交回给浏览器,让浏览器有工夫进行页面的渲染。等浏览器忙完之后,再持续之前未实现的工作。 旧版 React 通过递归的形式进行渲染,应用的是 JS 引擎本身的函数调用栈,它会始终执行到栈空为止。而Fiber实现了本人的组件调用栈,它以链表的模式遍历组件树,能够灵便的暂停、持续和抛弃执行的工作。实现形式是应用了浏览器的requestIdleCallback这一 API。官网的解释是这样的: window.requestIdleCallback()会在浏览器闲暇期间顺次调用函数,这就能够让开发者在主事件循环中执行后盾或低优先级的工作,而且不会对像动画和用户交互这些提早触发但要害的事件产生影响。函数个别会按先进先调用的程序执行,除非函数在浏览器调用它之前就到了它的超时工夫。有了解题思路后,咱们再来看看 React 具体是怎么做的。 四、React 的答卷React 框架外部的运作能够分为 3 层: Virtual DOM 层,形容页面长什么样。Reconciler 层,负责调用组件生命周期办法,进行 Diff 运算等。Renderer 层,依据不同的平台,渲染出相应的页面,比拟常见的是 ReactDOM 和 ReactNative。这次改变最大的当属 Reconciler 层了,React 团队也给它起了个新的名字,叫Fiber Reconciler。这就引入另一个关键词:Fiber。 ...

August 30, 2021 · 1 min · jiezi

关于react.js:React-Supense和React-异步渲染的一点矛盾

React的Suspense性能,简略说就是让组件渲染遇到须要异步操作的时候,能够无缝地“悬停”(suspense)一下,等到这个异步操作有后果的时候,再无缝地继续下去。 这里所说的异步操作,能够分为两类: 异步加载代码异步加载数据很好识别,写程序嘛,折腾的无外乎就是“代码”和“数据”这两样货色。 为什么要异步加载代码呢? 原本,代码打包成一个文件就行,然而当代码量很宏大,而且也不是所有代码都是页面加载的时候就用得上,把他们拉进惟一的打包文件,除了打包过程简略没有任何益处。所以,为了榨取性能,就要思考把代码打包成若干文件,这样每个打包文件就能够比拟小,依据须要来加载。这是一个好主见,不过让每个开发人员都实现这套机制也是够扯的,所以,React就用Suspense提供了对立的无缝的代码宰割(Code Splitting)兼异步加载办法,在v16.6.0就实现了这样的Suspense性能。 大家有趣味本人去玩,这种Suspense不是明天要讲的重点,明天要讲的是“异步加载数据”的Suspense,也就是利用Suspense来调用服务器API之类的操作。 依据React官网的路线图,利用Suspense来做数据加载,要等到往年(2019)的中期才公布,你如果看到这篇文章比拟晚,可能曾经公布了。 明天要说的,是Suspense做数据加载,和React v16的重头戏异步渲染有一点矛盾的中央。 在之前的Live 《深刻了解React v16新性能》中我说过,从React v16开始,一个组件的生命周期能够分为两个阶段:render阶段+commit阶段。在render阶段的生命周期函数,因为Fiber的设计特点,可能会被打断,被打断之后,会从新被调用;而commit阶段一旦开始,就绝不会被打断。render阶段和commit阶段的分界线是render函数,留神,render函数自身属于render阶段。 举个例子,一个组件被渲染,执行到render函数外面,这时候用户忽然在某个input控件里输出了什么,这时候React决定去优先解决input控件里的按键事件,就会打断这个组件的渲染过程,也就是不论render返回啥,渲染过程都就此打住,不画了,分心去解决input控件的事件去了。等到那边的事件解决完,再来渲染这个组件,然而这时候从原来地位从新开始,那必定是不靠谱的,因为方才的按键事件处理可能扭转了一些状态,为了保障相对靠谱,React决定……还是从头走一遍吧, 于是,从新去调getDerivedStateFromProps、shouldComponentUpdate而后调用render。 看到没哟,render之前的生命周期函数都会被调用,而且,因为这种“打断”是齐全是不可预期的,所以,当初就要求在render阶段的所有生命周期函数不要做有副作用的操作。 什么叫副作用?就是纯函数不该做的操作。 什么叫纯函数?就是除了依据输出参数返回后果之外,不做任何多与事件的操作。 如果一个函数批改全局变量,那就不是一个纯函数;如果一个函数批改类实例状态,那就不是一个纯函数;如果一个函数抛出异样,那就不是一个纯函数;如果一个函数通过AJAX拜访服务器API,那就不是一个纯函数。 就拿拜访服务器API为例,如果render阶段的生命周期函数做了拜访服务器API的AJAX操作,那么,很有可能产生间断对服务器的拜访,因为异步渲染下render阶段会被打断而反复执行啊。 class Foo extends React.Component { shouldComoponentUpdate() { callAPI(); // 你只看到了一行代码,然而可能会被屡次调用 return true; } render() { callAPI(); // 你只看到了一行代码,然而可能会被屡次调用 return JSX; }}再说一遍,在render阶段的所有生命周期函数不要做有副作用的操作,这些函数必须是纯函数。 那么,当初问题来了,应用Suspense来获取数据,会不会违反者这个规定呢? 尽管Suspense这方面的API还没有确定,然而代码模式还是明确的,利用试玩版的react-cache展现一下。 import React, { Suspense } from "react";import { unstable_createResource as createResource } from "react-cache";// 模仿一个AJAX调用const mockApi = () => { return new Promise((resolve, reject) => { setTimeout(() => resolve("Hello"), 1000); });};const resource = createResource(mockApi);const Greeting = () => { // 留神看这里,这里仍然是在render阶段,可能会被反复调用哦! const result = resource.read(); return <div>{result} world</div>;};const SuspenseDemo = () => { return ( <Suspense fallback={<div>loading...</div>}> <Greeting /> </Suspense> );};export default SuspenseDemo;这里就有意思了,应用Suspense来获取数据,既然数据是在render函数(或者像下面例子一样在函数类型组件中)应用,那么获取数据的过程必定是在render阶段,然而,获取数据的过程是要调用AJAX的啊,AJAX是副作用操作,这不就和“render阶段不能做有副作用操作“的规定矛盾了吗? ...

August 30, 2021 · 1 min · jiezi

关于react.js:电信杯网球积分赛微信小程序-总结

电信杯网球积分赛微信小程序是面向宽广网球爱好者,蕴含赛事一键报名,主动匹配参赛,多类型抉择,集体荣誉展现等性能,并配套相应的后盾管理系统。 这是本人第一次采纳Taro进行微信小程序的开发,相比于微信小程序,Taro开发中的很多问题都在网上找不到答案,就只有认真地去看官网文档和社区发问,这无疑也造就了本人看官网文档的习惯。 以下列举了本人开发中遇见的问题和解决办法 Canvas 绘制圆形图和环形进度条适配在选手首页展现排名和较量问题时呈现了字体移位和图像偏移的状况,在iphone5等老版本机型下及其显著。 在开发初期应用Canvas绘制的时,采纳了 query.arc(x, y, 0.8 * radius, 1.5 * Math.PI, endAngle, false);其绘图坐标下x,y没有绝对单位的束缚,故在不同机型下呈现问题. 解决方案: 查看微信适配的解决方案,能够应用api获取设施宽高比/750(微信小程序宽高) var SystemInfo=wx.getSystemInfoSync();通过这个能够取得用户零碎的信息,包含宽高的像素,你能够计算他们的比例,而后小程序里宽度都是750rpx,高度就通过那个宽高比取得,只有波及具体数值的高度的都通过这个比例计算就行在Taro中相似,最初在绘制时相应坐标乘以设施的Dp即可进行适配 import { getSystemInfoSync } from '@tarojs/taro';const facility = getSystemInfoSync(); // 获取设施信息const facility_width = facility.windowWidth; // 设施宽度const service.dp = facility_width / 750; 这次呈现谬误也让本人明确了提前明确标准的重要性,对字体,内外边距等提前进行标准,思考适配等问题 组件的复用,按状态渲染发现自己负责的问题填写页面会被复用拿来当作问题查看页面。效果图如下: 依据传入参数的不同又会分成这几种状态 解决方案 将组件每一局比分填写做成一个组件,依据状态来判断渲染,代码如下: <FillScoreCard tile={`第${index + 1}局`} allowInput={allowModify} returnScore= {this.getFillScore.bind(this,index)} initValue={e} />组件外部依据prop传入的状态渲染。 其余方面的优化因为本人只负责程序的一部分,但很多其余团队成员开发中遇见的问题本人也应该留神,等本人遇见的时候就不会不知所措了。

August 23, 2021 · 1 min · jiezi

关于react.js:从一个PR窥探React未来开发方式

大家好,我是卡颂。 都说Hooks是React的将来,但Hooks的最佳实际是什么呢? 对于这块常识,官网文档一点儿都没提及。 所以在理论我的项目中,常会呈现相似上面的问题: // ...useEffect(() => { fetchData(a, b).then( // ... )}, [a, b])//...useEffect依赖了a b两个状态,当其中任意一个变动后会执行fetchData申请数据。 当利用变得复杂,要追踪a、b何时变动变得越来越难。 假以时日接口调整,fetchData还须要状态c作为参数。那么追踪状态变动的难度又会进一步提高。 最终会导致: 轻则无意义的fetchData屡次调用重则逻辑呈现难以追究的bug有敌人会说:你能够封装自定义Hook啊。 这只是将问题暗藏的更深了...... 如何解决这个问题以上问题的实质起因是:副作用切实太多,能够被当作副作用的货色也切实太多。这导致useEffect被滥用。 所以,要解决滥用问题,就须要为不同类型副作用提供官网解决方案。 这样,具体问题有了具体解决方案,才不会useEffect一把梭。 从一个PR看到变动最近React有个很不起眼的PR: 大体意思是: 在之前,当你在一个曾经卸载的组件(unmounted)中调用setState会触发一个warning,这个PR将移除这个warning。 举个例子,以下代码在组件mount时注册handleChange: useEffect(() => { function handleChange() { setState(store.getState()) } store.subscribe(handleChange) return () => store.unsubscribe(handleChange)}, [])如果你遗记写这行解绑代码: return () => store.unsubscribe(handleChange)那么组件卸载后handleChange也可能被调用,进而调用setState。 这是潜在的内存透露。 在之前的React中,这种行为会报warning。 那为什么要移除这种行为下的warning呢? PR的背地一方面,这个warning有肯定概率误判,比方点击按钮提交表单: async function handleSubmit() { setPending(true) await post('/someapi') setPending(false)}点击按钮后调用setPending触发loading图标显示,接着发动post申请。 有可能申请返回前组件就卸载了,此时会调用: setPending(false)并不会有内存透露危险,然而会报warning。 不过warning移除还有另一个更实质的起因: 在第一个示例中,咱们在useEffect中调用store.subscribe,这种行为能够归类为: 在组件中订阅内部源什么是内部源呢? 任何变动与否不受React管制的源都是内部源。 ...

August 23, 2021 · 1 min · jiezi

关于react.js:React-的状态管理库-Recoil

为什么应用 Recoil在学一样货色之前,咱们得理解它为什么会诞生,或者是它解决了什么问题。 Recoil 是由 Facebook 推出的一个全新的、实验性的 JavaScript 状态治理库,它解决了应用现有 Context API 在构建大型利用时所面临的很多问题。 应用 React 内置的状态治理能力有这样一些局限性: 组件间的状态共享只能通过将 state 晋升至它们的公共先人来实现,但这样做可能导致从新渲染一颗微小的组件树。Context 只能存储繁多值,无奈存储多个各自领有 Consumer 的值的汇合。以上两种形式都很难将组件树的顶层(state 必须存在的中央)与叶子组件 (应用 state 的中央) 进行代码宰割。只管像 Redux 和 MobX 这样的库可能确保利用的状态保持一致,然而对于很多利用来讲,它们所带来的开销是难以估计的。 Redux、Mobx 自身并不是 React 库,咱们是借助这些库的能力来实现状态治理。像 Redux 它自身尽管提供了弱小的状态治理能力,然而应用的老本十分高,你还须要编写大量简短的代码,另外像异步解决或缓存计算也不是这些库自身的能力,甚至须要借助其余的内部库。 并且,它们并不能拜访 React 外部的调度程序,而 Recoil 在后盾应用 React 自身的状态,在将来还能提供并发模式这样的能力 Recoil 是什么Facebook 的软件工程师做过这样一个演讲分享 更新 List 外面第二个节点,而后心愿 Canvas 的第二个节点也跟着更新。 最古老的形式就是通过独特父子组件通信,但父组件上面的子组件都会更新,这种状况下个别应用  memo  或者  PureComponent。 还能够应用 React 自带的 Context API,将状态从父组件传给子组件。 但这样带来的问题就是如果咱们共享的状态越多就须要越多的 Provider,层层嵌套。 那是否有一种能够精准更新节点,同时又不须要嵌套太多层级的计划呢?它就是 Recoil。通过创立正交的 tree,将每个 state 和组件对应起来,从而实现精准更新。 Recoil 将这些 state 称之为 Atom(英文翻译为原子),顾名思义,Atom 是 Recoil 外面最小的数据单元,它反对更新和订阅。 ...

August 21, 2021 · 2 min · jiezi

关于react.js:React-setState和hooks

1. 函数组件const [state, setState] = useState('');setState本质:dispatchAction -> scheduleUpdateOnFiber2. class组件this.setState({}) -> enqueueSetState -> scheduleUpdateOnFibersetState是Component.prototype上的办法,constructClassInstance -> adoptClassInstance -> instance.update = classComponentUpdater

August 20, 2021 · 1 min · jiezi

关于react.js:React-Hooks

mountHooks 和 updateHooks 执行根本一样,多了 deps 判断mountWorkInProgressHook: 执行函数组件时 —— Component(props, secondArg),hooks 执行;挂载到 fiber.memoizedState 下function mountWorkInProgressHook() { var hook = { memoizedState: null, baseState: null, baseQueue: null, queue: null, next: null, }; if (workInProgressHook === null) { currentlyRenderingFiber$1.memoizedState = workInProgressHook = hook; } else { workInProgressHook = workInProgressHook.next = hook; } return workInProgressHook;}useEffectmountEffectImplfunction mountEffectImpl(fiberFlags: number, hookFlags: number, create, deps) { var hook = mountWorkInProgressHook(); var nextDeps = deps === undefined ? null : deps; currentlyRenderingFiber$1.flags |= fiberFlags; hook.memoizedState = pushEffect( HasEffect | hookFlags, create, undefined, nextDeps );}pushEffect: updateQueue 放入要更新到 effectfunction pushEffect(tag, create, destroy, deps) { var effect = { tag: tag, create: create, destroy: destroy, deps: deps, next: null, }; var componentUpdateQueue = currentlyRenderingFiber$1.updateQueue; if (componentUpdateQueue === null) { componentUpdateQueue = createFunctionComponentUpdateQueue(); currentlyRenderingFiber$1.updateQueue = componentUpdateQueue; componentUpdateQueue.lastEffect = effect.next = effect; } else { var lastEffect = componentUpdateQueue.lastEffect; if (lastEffect === null) { componentUpdateQueue.lastEffect = effect.next = effect; } else { var firstEffect = lastEffect.next; lastEffect.next = effect; effect.next = firstEffect; componentUpdateQueue.lastEffect = effect; } } return effect;}useStatemountStatefunction mountState(initialState) { var hook = mountWorkInProgressHook(); // 是办法,先执行失去 初始值 if (typeof initialState === "function") { initialState = initialState(); } hook.memoizedState = hook.baseState = initialState; var queue = (hook.queue = { pending: null, dispatch: null, lastRenderedReducer: basicStateReducer, lastRenderedState: initialState, }); var dispatch = (queue.dispatch = dispatchAction.bind( null, currentlyRenderingFiber$1, queue )); return [hook.memoizedState, dispatch];}

August 20, 2021 · 2 min · jiezi

关于react.js:React-Fiber

FiberRoot创立 FiberRoot 和 RootFiber,应用 stateNode 和 currentfunction createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks) { var root = new FiberRootNode(containerInfo, tag, hydrate); var uninitializedFiber = createHostRootFiber(tag); root.current = uninitializedFiber; uninitializedFiber.stateNode = root; initializeUpdateQueue(uninitializedFiber); return root;}FiberRoot 类function FiberRootNode(containerInfo, tag, hydrate) { this.tag = tag; this.containerInfo = containerInfo; this.pendingChildren = null; this.current = null; this.pingCache = null; this.finishedWork = null; this.timeoutHandle = noTimeout; this.context = null; this.pendingContext = null; this.hydrate = hydrate; this.callbackNode = null; this.callbackPriority = NoLanePriority; this.eventTimes = createLaneMap(NoLanes); this.expirationTimes = createLaneMap(NoTimestamp); this.pendingLanes = NoLanes; this.suspendedLanes = NoLanes; this.pingedLanes = NoLanes; this.expiredLanes = NoLanes; this.mutableReadLanes = NoLanes; this.finishedLanes = NoLanes; this.entangledLanes = NoLanes; this.entanglements = createLaneMap(NoLanes); { this.mutableSourceEagerHydrationData = null; } { this.interactionThreadID = tracing.unstable_getThreadID(); this.memoizedInteractions = new Set(); this.pendingInteractionMap = new Map(); } { switch (tag) { case BlockingRoot: this._debugRootType = "createBlockingRoot()"; break; case ConcurrentRoot: this._debugRootType = "createRoot()"; break; case LegacyRoot: this._debugRootType = "createLegacyRoot()"; break; } }}tag 类型export const FunctionComponent = 0; // 函数组件export const ClassComponent = 1; // 类组件export const IndeterminateComponent = 2; // 初始化的时候不晓得是函数组件还是类组件export const HostRoot = 3; // Root Fiber 能够了解为跟元素 , 通过reactDom.render()产生的根元素export const HostPortal = 4; // 对应 ReactDOM.createPortal 产生的 Portalexport const HostComponent = 5; // dom 元素 比方 <div>export const HostText = 6; // 文本节点export const Fragment = 7; // 对应 <React.Fragment>export const Mode = 8; // 对应 <React.StrictMode>export const ContextConsumer = 9; // 对应 <Context.Consumer>export const ContextProvider = 10; // 对应 <Context.Provider>export const ForwardRef = 11; // 对应 React.ForwardRefexport const Profiler = 12; // 对应 <Profiler/ >export const SuspenseComponent = 13; // 对应 <Suspense>export const MemoComponent = 14; // 对应 React.memo 返回的组件Fiber 类function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; this.elementType = null; this.type = null; this.stateNode = null; this.return = null; this.child = null; this.sibling = null; this.index = 0; this.ref = null; this.pendingProps = pendingProps; this.memoizedProps = null; this.updateQueue = null; this.memoizedState = null; this.dependencies = null; this.mode = mode; this.flags = NoFlags; this.nextEffect = null; this.firstEffect = null; this.lastEffect = null; this.lanes = NoLanes; this.childLanes = NoLanes; this.alternate = null; { this.actualDuration = Number.NaN; this.actualStartTime = Number.NaN; this.selfBaseDuration = Number.NaN; this.treeBaseDuration = Number.NaN; this.actualDuration = 0; this.actualStartTime = -1; this.selfBaseDuration = 0; this.treeBaseDuration = 0; } { this._debugID = debugCounter++; this._debugSource = null; this._debugOwner = null; this._debugNeedsRemount = false; this._debugHookTypes = null; if (!hasBadMapPolyfill && typeof Object.preventExtensions === "function") { Object.preventExtensions(this); } }}WorkInProgress 类function createWorkInProgress(current, pendingProps) { var workInProgress = current.alternate; if (workInProgress === null) { workInProgress = createFiber( current.tag, pendingProps, current.key, current.mode ); workInProgress.elementType = current.elementType; workInProgress.type = current.type; workInProgress.stateNode = current.stateNode; { // DEV-only fields workInProgress._debugID = current._debugID; workInProgress._debugSource = current._debugSource; workInProgress._debugOwner = current._debugOwner; workInProgress._debugHookTypes = current._debugHookTypes; } workInProgress.alternate = current; current.alternate = workInProgress; } else { workInProgress.pendingProps = pendingProps; workInProgress.type = current.type; workInProgress.flags = NoFlags; workInProgress.nextEffect = null; workInProgress.firstEffect = null; workInProgress.lastEffect = null; { workInProgress.actualDuration = 0; workInProgress.actualStartTime = -1; } } workInProgress.childLanes = current.childLanes; workInProgress.lanes = current.lanes; workInProgress.child = current.child; workInProgress.memoizedProps = current.memoizedProps; workInProgress.memoizedState = current.memoizedState; workInProgress.updateQueue = current.updateQueue; var currentDependencies = current.dependencies; workInProgress.dependencies = currentDependencies === null ? null : { lanes: currentDependencies.lanes, firstContext: currentDependencies.firstContext, }; workInProgress.sibling = current.sibling; workInProgress.index = current.index; workInProgress.ref = current.ref; { workInProgress.selfBaseDuration = current.selfBaseDuration; workInProgress.treeBaseDuration = current.treeBaseDuration; } { workInProgress._debugNeedsRemount = current._debugNeedsRemount; switch (workInProgress.tag) { case IndeterminateComponent: case FunctionComponent: case SimpleMemoComponent: workInProgress.type = resolveFunctionForHotReloading(current.type); break; case ClassComponent: workInProgress.type = resolveClassForHotReloading(current.type); break; case ForwardRef: workInProgress.type = resolveForwardRefForHotReloading(current.type); break; } } return workInProgress;}

August 20, 2021 · 3 min · jiezi

关于react.js:React-commitRoot

commitRoot全局变量 workInProgressRoot、workInProgress、workInProgressRootRenderLanes 设为 默认值获取 workInProgress 上的 firstEffect(completeUnitOfWork 生成的) if (finishedWork.flags > PerformedWork) { if (finishedWork.lastEffect !== null) { finishedWork.lastEffect.nextEffect = finishedWork; firstEffect = finishedWork.firstEffect; } else { firstEffect = finishedWork; }}commitBeforeMutationEffectsbefore mutation: 对不同组件进行操作 class 组件: 获取 snapshot其余组件: 不解决commitMutationEffects将组件退出到实在的 dom 节点下 —— div#root.appendChild(child)HostComponent: commitUpdate 进行事件注册commitLayoutEffects性能ref 挂载: commitAttachRef: ref.current = current.stateNodecommitLifeCycles 函数组件: commitHookEffectListMount —— 取出 finishedWork.updateQueue,执行外面的 hooksclass 组件: 执行生命周期办法, componentDidUpdate(props, state, snapshot)commitUpdateQueue代码commitUpdateQueue: 执行 updateQueue 中的办法 function commitUpdateQueue(finishedWork, finishedQueue, instance) { var effects = finishedQueue.effects; finishedQueue.effects = null; if (effects !== null) { for (var i = 0; i < effects.length; i++) { var effect = effects[i]; var callback = effect.callback; if (callback !== null) { effect.callback = null; callCallback(callback, instance); } } }}

August 20, 2021 · 1 min · jiezi

关于react.js:React-completeUnitOfWork

completeUnitOfWork: 失去要更新的 Fiber,造成链表paramsunitOfWork代码if (returnFiber !== null && (returnFiber.flags & Incomplete) === NoFlags) { if (returnFiber.firstEffect === null) { returnFiber.firstEffect = completedWork.firstEffect; } if (completedWork.lastEffect !== null) { if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = completedWork.firstEffect; } returnFiber.lastEffect = completedWork.lastEffect; } var flags = completedWork.flags; if (flags > PerformedWork) { if (returnFiber.lastEffect !== null) { returnFiber.lastEffect.nextEffect = completedWork; } else { returnFiber.firstEffect = completedWork; } returnFiber.lastEffect = completedWork; }}

August 20, 2021 · 1 min · jiezi

关于react.js:React-reconcileChildren

reconcileChildrenparamscurrentworkInProgressnextChildren class 组件: instance.render()函数组件: return 的值renderLanesfunction reconcileChildren(current, workInProgress, nextChildren, renderLanes) { if (current === null) { workInProgress.child = mountChildFibers( workInProgress, null, nextChildren, renderLanes ); } else { workInProgress.child = reconcileChildFibers( workInProgress, current.child, nextChildren, renderLanes ); }}reconcileChildFibersparamsreturnFibercurrentFirstChildnewChild class 组件: instance.render()函数组件: return 的值lanesfunction reconcileChildFibers(returnFiber, currentFirstChild, newChild, lanes) { var isUnkeyedTopLevelFragment = typeof newChild === "object" && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; if (isUnkeyedTopLevelFragment) { newChild = newChild.props.children; } var isObject = typeof newChild === "object" && newChild !== null; if (isObject) { switch (newChild.$$typeof) { // reconcileSingleElement case REACT_ELEMENT_TYPE: return placeSingleChild( reconcileSingleElement( returnFiber, currentFirstChild, newChild, lanes ) ); case REACT_PORTAL_TYPE: return placeSingleChild( reconcileSinglePortal(returnFiber, currentFirstChild, newChild, lanes) ); } } if (typeof newChild === "string" || typeof newChild === "number") { return placeSingleChild( reconcileSingleTextNode( returnFiber, currentFirstChild, "" + newChild, lanes ) ); } // 数组时 if (isArray$1(newChild)) { return reconcileChildrenArray( returnFiber, currentFirstChild, newChild, lanes ); } if (getIteratorFn(newChild)) { return reconcileChildrenIterator( returnFiber, currentFirstChild, newChild, lanes ); } if (isObject) { throwOnInvalidObjectType(returnFiber, newChild); } { if (typeof newChild === "function") { warnOnFunctionType(returnFiber); } } if (typeof newChild === "undefined" && !isUnkeyedTopLevelFragment) { switch (returnFiber.tag) { case ClassComponent: { { var instance = returnFiber.stateNode; if (instance.render._isMockFunction) { break; } } } case Block: case FunctionComponent: case ForwardRef: case SimpleMemoComponent: { { { throw Error( (getComponentName(returnFiber.type) || "Component") + "(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null." ); } } } } } return deleteRemainingChildren(returnFiber, currentFirstChild);}createFiberFromElementparamselement: ReactElement 对象modelanes性能执行 createFiberFromTypeAndProps,创立 Fiber ...

August 20, 2021 · 2 min · jiezi

关于react.js:React-beginWork

beginWorkparamscurrent: mount 时:只有 rootFiber 和 rootWorkInProgrss 的 current !== null;其余 current = nullworkInProgressrenderLanes依据 tag 执行不同办法;mountIndeterminateComponent: 不确定是 function 还是 classupdateFunctionComponent: renderWithHooksreconcileChildrenupdateClassComponent: 代码如下// 没有实例对象if (instance === null) { // 有 current 对象 if (current !== null) { current.alternate = null; workInProgress.alternate = null; workInProgress.flags |= Placement; } /** * 1. 创立实例对象,将 state 挂载到 memoizedState * 2. 执行 adoptClassInstance */ constructClassInstance(workInProgress, Component, nextProps); /** * 1. initializeUpdateQueue: 初始化 fiber 的 updateQueue * 2. processUpdateQueue: 计算 state 值 */ mountClassInstance(workInProgress, Component, nextProps, renderLanes); shouldUpdate = true;} else if (current === null) { // 有实例对象,没有 current 对象 // 重用 instace 值 shouldUpdate = resumeMountClassInstance( workInProgress, Component, nextProps, renderLanes );} else { /** * 1. cloneUpdateQueue * 2. processUpdateQueue */ shouldUpdate = updateClassInstance( current, workInProgress, Component, nextProps, renderLanes );}reconcileChildrenupdateHostRoot: FiberRoot ...

August 20, 2021 · 4 min · jiezi

关于react.js:React-render过程

ReactDOM.render()第一次渲染,入口renderparamselement: 通过 babel 编译后 React.createElement 对象container: dom 对象,div#rootcallback: 渲染实现后到回调函数(不须要关注,个别没用)legacyRenderSubtreeIntoContainerparamsparentComponent: nullchildren: React.createElementcontainer: div#rootforceHydrate: false; 客户端渲染 和 服务端渲染 辨别标识callback性能创立 FiberRoot 和 RootFiberupdateContainerparamselement: React.createElementcontainer: FiberRootparentComponentcallback性能通过 rootFiber 失去 lane创立 update 对象,放到 updateQueue 中scheduleUpdateOnFiberparamsfiberlaneeventTime性能获取 fiber 的 root: markUpdateLaneFromFiberToRootperformSyncWorkOnRootparamsroot: FiberRoot性能执行 renderRoot 和 commitRootroot.finishedWork = root.current.alternate(workInProgress)root.finishedLanes = lanes;renderRootparamsrootlanes性能创立 workInProgress: prepareFreshStackroot.finishedWork 、 finishedLanes 复原默认值workInProgressRoot = root;给全局 workInProgress 赋值执行 workLoopworkLoop性能执行 while 循环: 判断条件—— workInProgress !== null;(只有 rootFiber.return 是 null)performUnitOfWorkparamsunitOfWork: workInProgress性能执行 beginWork执行 completeUnitOfWorkcommitRootparamsroot

August 20, 2021 · 1 min · jiezi

关于react.js:hoc实现表单组件的设计思路

前言通过模拟 rc-form 的实现思路,能够学习一下 hoc 的应用场景。 裸露 createForm() 函数通过 createForm 函数,返回一个组件。该组件拓展了咱们的一些办法。 export function createForm(Cmp) { return class extends Component { getFieldDecorator = () => {} getFieldsValue = () => {} getFieldValue = () => {} setFieldValue = () => {} validateFields = () => {} form = () => { return { getFieldDecorator: this.getFieldDecorator, getFieldValue: this.getFieldValue, getFieldsValue: this.getFieldsValue, setFieldValue: this.setFieldValue, validateFields: this.validateFields, } } render() { const form = getForm() return <Cmp {...this.props} form={form} /> } }}实现 getFieldDecorator应用办法 ...

August 20, 2021 · 2 min · jiezi

关于react.js:react开发侧边栏背景与浮动Menu设计

侧边栏背景设计:step1:导入背景图片 background-image: url(../../assets/menu-background.png);background-repeat:no-repeat ;background-size: cover;step2:设置背景图片高度 父盒子高度就是所有可见区高度height:100%;父盒子高度中蕴含其余盒子height: ~'calc(100% - @{layout-header-height})';背景图片须要设计为滚动条可见区高度const scrollHight = document.body.scrollHeight;style={{ height:{scrollHight}}}浮动Menu设计step1:导入andt组件<Menu> `import { Menu } from 'antd';`step2:<div>(menu的父元素)中导入menu的背景图片并设置浮动 background-image: url(../../assets/menu-focusing.png);background-repeat:no-repeat ;background-size: cover;position: fixed;step3:写出menu的style和题目 <Menu className={addStyles.newStyle}><SubMenu title="我的项目合集" className={addStyles.writeSize}>{this.getProjectData()}</SubMenu><div className={addStyles.backLogo} /step4:getProjectData()函数获取数据,并获得前5(NUMBER_FIVE)条数据,再通过数据驱动生成menuitem获取数据getProjectData = () => { const { ProjectModel = {} } = this.props; const { Topdata = [""] } = ProjectModel; const getedData = []; for (let i = 0; i < Topdata.length; i += 1) { if (Topdata.length !== 0) { const { projectName = [] } = Topdata[i]; getedData[i] = projectName; } } if (getedData.length >NUMBER_FIVE) { for (let j = NUMBER_FIVE; j <= getedData.length - 1; j += 1) { getedData.pop(); } } return ( getedData.map((rigthData) => ( this.createProjectMenu(rigthData) ))) }createProjectMenu()函数生成menuitem createProjectMenu = (rigthData) => { const { changeStyle = ''} = this.state; const { ProjectModel = {} } = this.props; const { Topdata = [""] } = ProjectModel; return ( <div> <Menu> <Menu.Item className={addStyles.menuItemStyle}> <Button onClick={this.goTheProject} className={addStyles.buttonStyle}> {rigthData} </Button> </Menu.Item> <span> <Button className={addStyles.anoButtonStyle} onClick={() => this.changeIcon(Topdata)}> <Icon type="star" style={{ fontSize: '30px' }} theme={changeStyle === 1 ? ("twoTone") : ("")} twoToneColor={changeStyle === 1 ? ("#52c41a") : ("")} /> </Button> </span> </Menu> </div> ) }goTheProject()函数:通过点击事件进行跳转,跳转到该项目标详情页面goTheProject = () => { router.push({ pathname: '/Project/ProjectBranch' }); }changeIcon()函数:通过点击图标进行珍藏和勾销珍藏const { confirm } = Modal;changeIcon = (record) => { const { isChange } = this.state; const { dispatch, ProjectModel: { pagination } } = this.props; const data = record[0]; const { id = '' } = data; this.setState({ visible: true }) if (isChange === 1) { this.setState( { changeStyle: 0, isChange: 0, } ) confirm({ title: `是否勾销珍藏所选我的项目`, okText: '确定', cancelText: '勾销', onOk: () => { dispatch({ type: 'ProjectModel/deleteTopProject', payload: { data: { projectId: id, }, pagination, }, }); }, }); } else { this.setState( { changeStyle: 1, isChange: 1, } ) confirm({ title: `是否珍藏所选我的项目`, okText: '确定', cancelText: '勾销', onOk: () => { dispatch({ type: 'ProjectModel/topProject', payload: { data: { projectId: id, }, pagination, }, }); }, }); } }

August 18, 2021 · 2 min · jiezi

关于react.js:React-state-基础使用

import React, { Component } from 'react' class index extends Component { constructor(props) { super(props) this.state = { count:10, name:'小刘', obj: { a: 1, b: 2, c:3, } }} setName() { // const { name } = this.state; this.setState({ name:'老刘' })} setA() { // const { obj } = this.state; const obj = Object.assign({},this.state.obj, { a:10}) setTimeout(() => { this.setState({ obj:obj }) },1000)}setB() { const b={b:20} const obj = { ...this.state.obj, ...b } setTimeout(() => { this.setState({ obj:obj }) },2000) } componentDidMount() { ...

August 18, 2021 · 1 min · jiezi

关于react.js:mobx安装及其简单使用

装置:yarn add mobx(独自的js 文件)yarn add mobx-react(react和mobx进行绑定)父组件 数据注入子组件 获取(任意组件) 新建store/store.jsimport {observable, computed, action, autorun,runInAction} from 'mobx';// import {observable, computed, action} from 'mobx';class Store { @observable tradeCfg = { 'sadf':'sadf' }; @observable baseInfo = {}; @observable callback = null; @observable token = [ { "id":1, "name":"YD" }, { "id":2, "name":"ETH" } ];}export default Store;关上Router.js第一步:引入store文件和mobx-react第二步:定义一个对象,用Provider将App进行包裹 const stores = { FStore: new FirstStore(),}父级注入治理1、引入mobx-react Provider2、引入store.js new Store()引入一个新的store.jsstores = { newStore: new newStore(), newStore1: new newStore1(), newStore2: new newStore2(),}3、Provider 注入 {...store} ...

August 18, 2021 · 1 min · jiezi

关于react.js:React-mobx-基础使用

组件通信 propscontextredux mobox 任意组件间的数据通信### mobx 会有一个独自的js文件进行治理 父组件 数据注入 Provider 子组件 (任意组件) 装置 yarn add mobx npm install mobx --save 有一个包父级的入口治理引入 mobx-react 应用Provider引入store.js 中的文件 (可能是多个) new Store() 增加 - 引入一个新的store stores={newStore:new NewStore(),} 应用Provider 注入 { ...stores }### 报错 因为mobx 不反对@语法所以会报错// import {observable, computed, action} from 'mobx';3 | class Store {> 4 | @observable tradeCfg = { | ^5 | 'sadf': 'sadf'6 | };7 | @observable baseInfo = {};<!-- 解决方案: yarn add @babel/plugin-proposal-decorators yarn add @babel/plugin-proposal-class-properties -->解决办法 ...

August 17, 2021 · 2 min · jiezi

关于react.js:React-Mobx-基础使用01

组件通信 propscontextredux mobox 任意组件间的数据通信### mobx 会有一个独自的js文件进行治理 父组件 数据注入 Provider 子组件 (任意组件) 装置 yarn add mobx npm install mobx --save 有一个包父级的入口治理引入 mobx-react 应用Provider引入store.js 中的文件 (可能是多个) new Store() 增加 - 引入一个新的store stores={newStore:new NewStore(),} 应用Provider 注入 { ...stores }### 报错 因为mobx 不反对@语法所以会报错// import {observable, computed, action} from 'mobx';3 | class Store {> 4 | @observable tradeCfg = { | ^5 | 'sadf': 'sadf'6 | };7 | @observable baseInfo = {};<!-- 解决方案: yarn add @babel/plugin-proposal-decorators yarn add @babel/plugin-proposal-class-properties -->解决办法 ...

August 17, 2021 · 1 min · jiezi

关于react.js:antd-key报错-Each-child-in-a-list-should-have-a-unique-key-prop

应用 react + antd 组件时,有时会报出 Each child in a list should have a unique "key" prop. 这样的谬误 这里列举几个相干的次谬误报错和解决形式 1、Table 表格 官网给 Table 组件提供了一个 rowKey 属性,用于给表格的每一行设定一个 key 值 如:<Table columns={columns} dataSource={users.data} rowKey={columns => columns.id} />2、Select 选择器 中的 Option 应用 map() 办法动静增加选项,也须要给 <Option> 设置 key 属性3、应用 map() 遍历渲染时,也会报出 key 值的谬误 给被遍历的组件加上 key 属性4、Modal 对话框 给页脚组件设置 key 属性 转自https://blog.csdn.net/AS_TS/a...

August 16, 2021 · 1 min · jiezi

关于react.js:react版本markdown编辑器mdeditorrt支持ssr

md-editor-rt是前段时间学习vue3时开发的一个vue3版本编辑器md-editor-v3的同系列我的项目,它是react版本的,因为vue3版本的也是应用tsx实现的,所以react版本的代码相差不大。 作者的博客前端内容是应用nextjs开发的,而内容治理又是应用vue开发的,提取编辑文章和内容渲染的性能造成了这个我的项目。1. 预览1.1 性能预览快捷插入内容工具栏、编辑器浏览器全屏、页面内全屏等;内置的红色主题和暗黑主题,反对绑定切换;反对快捷键插入内容;反对应用 prettier 格式化内容(应用 CDN 形式引入,只反对格式化 md 内容,可在代码内设置敞开);反对多语言,反对自行扩大语言;反对复制粘贴上传图片,图片裁剪上传;反对渲染模式(不显示编辑器,只显示 md 预览内容,无额定监听);反对ssr,反对在nextjs中应用;1.2 在线预览文档与在线预览:传送门 1.3 图片预览默认模式 暗黑模式 2. 根本应用react版本目前没有导出umd版本。 2.1 惯例单页利用import React, { useState } from 'react';import Editor from 'md-editor-rt';import './index.less';export default () => { const [md, setMd] = useState(''); return <Editor theme="dark" modelValue={md} onChange={(v) => setMd(v)} />;};2.2 服务端渲染服务端渲染的状况个别是提供markdown文本渲染内容而非加载整个编辑器,上面的例子即是应用仅预览模式的状况。 import React, { useState } from 'react';import Editor from 'md-editor-rt';import './index.less';export default () => { const [md] = useState('# title'); // 仅预览模式只需提供md文本而不会扭转文本 return <Editor editorId="article-content" theme="dark" modelValue={md} previewOnly />;};从写法来讲,没有区别,值得注意的是,服务端渲染时最好提供editorId属性,因为默认状况下编辑器会随机生成editorId,所以会造成服务端的html内容和客户端渲染的html内容不统一而提醒谬误(该问题在nextjs根底环境中能够重现)。 ...

August 13, 2021 · 2 min · jiezi

关于react.js:React源码解读

1. 配置 React 源码本地调试环境应用 create-react-app 脚手架创立我的项目 npx create-react-app react-test 弹射 create-react-app 脚手架外部配置 npm run eject 克隆 react 官网源码 (在我的项目的根目录下进行克隆) git clone --branch v16.13.1 --depth=1 https://github.com/facebook/react.git src/react 链接本地源码 // 文件地位: react-test/config/webpack.config.jsresolve: { alias: { "react-native": "react-native-web", "react": path.resolve(__dirname, "../src/react/packages/react"), "react-dom": path.resolve(__dirname, "../src/react/packages/react-dom"), "shared": path.resolve(__dirname, "../src/react/packages/shared"), "react-reconciler": path.resolve(__dirname, "../src/react/packages/react-reconciler"), "legacy-events": path.resolve(__dirname, "../src/react/packages/legacy-events") }}批改环境变量 // 文件地位: react-test/config/env.jsconst stringified = { "process.env": Object.keys(raw).reduce((env, key) => { env[key] = JSON.stringify(raw[key]) return env }, {}), __DEV__: true, SharedArrayBuffer: true, spyOnDev: true, spyOnDevAndProd: true, spyOnProd: true, __PROFILE__: true, __UMD__: true, __EXPERIMENTAL__: true, __VARIANT__: true, gate: true, trustedTypes: true }通知 babel 在转换代码时疏忽类型查看 ...

August 13, 2021 · 34 min · jiezi

关于react.js:react-propTypes-Typescript

最近看官网的文档,看到了 应用 PropTypes 进行类型查看 这一章节,看完之后发现这玩意和typeScript 很相似,所以查找了一些材料,发现他们是能够相互转换的,上面来看一些例子: 根本类型的定义 PropTypes写法: // 当然要引入(以下省略)import PropTypes from 'prop-types';Example.propTypes = { message: PropTypes.string, // 定义 string 类型 count: PropTypes.number, // 定义 number 类型 disabled: PropTypes.bool, // 定义 boolen 类型 level: PropTypes.symbol, // 定义 symbol 类型}TypeScript 的写法: interface Props { message: string; count: number; disabled: boolean; level: Symbol;}一些非凡的类型 PropTypes写法: Example.propTypes = { error: PropTypes.instanceOf(Error), // 是否是 error 实例 children: PropTypes.node, // 定义 元素 status: PropTypes.oneOf(['inactive', 'inProgress', 'success', 'failed']), // 定义指定值,必须为 'inactive', 'inProgress', 'success', 'failed' 中的一个 value: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Error), ]), // 必须为这几种类型中的一种}TypeScript 的写法: ...

August 12, 2021 · 2 min · jiezi

关于react.js:react自定义video视频播放样式鼠标移入播放移出停止

video标签默认视频播放款式: 更改后的播放成果: 代码: const [playStatus, setPlayStatus] = useState(new Array(4)); // 视频的播放状态,用于控住播放按钮的显示与暗藏const videos = () => { const ref: (HTMLVideoElement | null)[] = []; return ( <ul styleName="content-video"> // videosConfig存储一组视频的url {videosConfig.map((e, i) => ( <div styleName="video-item" key={e.fileUrl}> <video muted src={e.fileUrl} ref={el => { ref[i] = el; }} onMouseOver={() => { ref[i] && ref[i]?.play(); playStatus[i] = true; setPlayStatus([...playStatus]); }} onMouseOut={() => { ref[i] && ref[i]?.pause(); playStatus[i] = false; setPlayStatus([...playStatus]); }} key={e.fileUrl} width="250px" height="430px" /> {!playStatus[i] && <Play />} // 为false时显示播放按钮<Play />组件为播放按钮svg图 </div> ))} </ul> );Play组件: ...

August 11, 2021 · 1 min · jiezi

关于react.js:Redux及Reactredux的简单使用

在react我的项目中应用redux的简略案例 脚手架 create-react-app 1.装置reduxnpm install redux --save 2.redux store目录文件调配 -- action.js 动作 --reducers 计算属性汇合文件夹 -- index.js 计算模块进口 -- user.js 计算模块1 -- test.js 计算模块2 -- store.js redux的store 进口 -- type.js action 动作名称类型构造案例 3. store代码1.action.js 动作整合模块 import types from '../type.js'; //View视图 要发送多少种音讯,这里就封装多少种 // 调用 user.js 中的计算属性export const userAction=(data)=>({type:types.USER,data}); // 调用 token.js 中的计算属性export const userTokenAction=(data)=>({type:types.TOKEN,data}); 2.type.js 常量名称类别封装 export default { TOKEN:'TOKEN', USER:'USER', USER_NAME:'USER_NAME', }3. reducers 计算属性整合user.js 计算模块1 (PS: 计算模块的js 文件 分成多个 还是 写成一个 随本身需要,这里举例 只写 一个,token.js 和 user.js 是统一的) ...

August 8, 2021 · 2 min · jiezi

关于react.js:使用TypescriptReact-hooks实现滑动点赞的组件

自从React推出hooks后,函数式组件如同能够配合hooks做任何事了,不必class component也能实现各种性能了,而且这种模式更加灵便,更易于拆分与封装。一番体验下来,充沛意识到,函数式编程+hooks才是React的王道。明天咱们就来应用hooks来实现一下滑动列表项显示点赞按钮的性能。页面如下所示: 梳理一下性能:滑动列表条目时,左滑显示点赞按钮,并且关掉其余条目标按钮显示;右滑,关掉以后条目标点赞按钮展现。 其实这个性能实现起来没有什么难度,只是给列表条目绑定touchmove事件,左滑的时候,增加款式,使条目左移,显示出点赞按钮。咱们间接上代码看看: // index.tsximport React from 'react';import './index.less';import { newsItem } from '../../types';import useSwipe from '../../hooks/useSwiper';const newsListData = [ { id: 1, title: '菲律宾多位学者发动网上请愿', src: 'pic.png', abstract: '菲律宾多位学者5日发动网上请愿流动,心愿收集足够多的签名。', releaseDate: '2021-08-06 15:42', like: false, }, { id: 2, title: '疏导粉丝文化步入衰弱轨道', src: 'pic1.png', abstract:'各相干方都要负起社会责任,保持正确导向,盲目做社会正能量的放大器', releaseDate: '08-05 06:30', like: false, },];function SwiperItem({ title, src, abstract, releaseDate, isCurrent, like, swipeEventHandler, likeEventHandler,}: newsItem) { return ( <div className="swiper-list-item" {...swipeEventHandler}> <div className={[ 'item-content-wrap', isCurrent ? 'swiper-left' : '', ].join(' ')} > <img className="news-pic" src={src} alt={title} /> <div className="item-right-content"> <p className="news-title">{title}</p> <p className="news-abstract">{abstract}</p> <p className="news-publish-date">公布工夫:{releaseDate}</p> </div> </div> <div className="like-btn" {...likeEventHandler}> {like ? '勾销' : '点赞'} </div> </div> );}export default function SwiperList() { const { swipeList, createSwipeProps, createLikeProps } = useSwipe(newsListData); return ( <div className="swiper-list-cpn"> {swipeList.map((item) => ( <SwiperItem key={item.id} {...{ ...item, ...createSwipeProps(item.id), ...createLikeProps(item.id), }} /> ))} </div> );}// useSwipe.tsimport { useState } from 'react';import { newsItem } from '../types';function setSwipeLeftList(list: Array<newsItem>, id: number): Array<newsItem> { return list.map((item) => ({ ...item, isCurrent: item.id === id, }));}function setSwipeRightList(list: Array<newsItem>): Array<newsItem> { return list.map((item) => ({ ...item, isCurrent: false, }));}function setLikeList(list: Array<newsItem>, id: number): Array<newsItem> { return list.map((item) => ({ ...item, like: item.id === id ? !item.like : item.like, }));}export default function useSwipe(list: Array<newsItem>) { const [swipeList, setSwipeList] = useState(list); const [preId, setPreId] = useState(-1); const [startX, setStartX] = useState(0); return { swipeList, createSwipeProps: (id: number) => { return { swipeEventHandler: { onTouchStart: (e: React.TouchEvent) => { // 滑动初始地位 setStartX(e.targetTouches[0].clientX); }, onTouchEnd: (e: React.TouchEvent) => { const endX = e.changedTouches[0].clientX; const deltaX = startX - endX; if (deltaX > 50) { // 左滑 if (id === preId) return; setSwipeList(setSwipeLeftList(swipeList, id)); setPreId(id); } else if (deltaX < -50) { // 右滑 if (id !== preId) return; setSwipeList(setSwipeRightList(swipeList)); setPreId(-1); } }, }, }; }, createLikeProps: (id: number) => { return { likeEventHandler: { onClick: () => { setTimeout(() => { setSwipeList(setLikeList(swipeList, id)); }, 100); }, }, }; }, };}// index.less.swiper-list-cpn { padding: 20px; .swiper-list-item { position: relative; height: 140px; margin-bottom: 20px; border-radius: 4px; overflow: hidden; box-shadow: 2px 2px 5px grey; .item-content-wrap { position: absolute; left: 0; top: 0; z-index: 1; display: flex; align-items: center; height: 100%; box-sizing: border-box; padding: 10px 20px; background: #fff; transition: transform 0.3s ease-in; &.swiper-left { transform: translateX(-60px); } .news-pic { width: 80px; margin-right: 20px; } .item-right-content { flex: 1; .news-title { margin-bottom: 10px; font-size: 16px; font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .news-abstract { margin-bottom: 10px; font-size: 14px; } .news-publish-date { font-size: 12px; color: grey; } } } .like-btn { position: absolute; right: 0; top: 0; width: 60px; line-height: 140px; text-align: center; background: rgb(255, 66, 66); } }}看代码的构造的话,我把整个逻辑层抽离进去一个自定义hook,这个hook很简略,我的列表是依据列表的数据渲染进去的,所以其实我只须要跟列表的数据打交道就行了,不论是左滑右滑还是点赞勾销点赞,都只是扭转列表的数据内容,扭转后再渲染到页面上。Hooks很弱小,也很灵便,这既是长处也是毛病,如果你能很好进行模块的拆解与封装,那么代码的可读性和可维护性会很高,反之,简略的怼hooks,前期保护将是劫难。 ...

August 7, 2021 · 2 min · jiezi

关于react.js:lernaumiantdqiankun-搭建微服务过程

背景公司一个开发迭代两年的我的项目因前期须要扩大更多的业务板块须要进行拆分,一是要满足前期一直新增板块业务不对现有业务产生影响,再者就是目前存在单我的项目业务量过大,开发保护难度极大,于是不得不思考将现有业务板块进行微服务化拆分,以满足前期的需要。 此文是对题目采纳技术栈实现过程的技术分享,同时也是对该技术计划的摸索和实际,感兴趣的同学请留步! lerna一个用于治理带有多个包的 JavaScript 我的项目的工具。 次要用于微服务生产阶段公共依赖的治理。能够解决的问题:开发阶段多服务同时启动,子项目不必放在同一个 git 我的项目中,企业中局部 npm 私服包能够更便捷的更新到各个子项目等,将局部公共依赖装置在lerna根目录能够节俭一部分存储空间。 疾速上手PS:这里须要先新建一个空的我的项目目录,以下示例均为umi-qiankun-explore 倡议将lerna装置在全局,当然也能够装置在我的项目部分 npm i lerna -g初始化 lerna init --independent //装置在全局 npx lerna init --independent //装置在部分次要办法,既能够给某个我的项目独自装置依赖,也能够给所有子项目装置公共依赖,具体反对的参数见lerna bootstrap lerna bootstrap <--options>初始化后的 lerna 我的项目目录如下 umi-qiankun-explore/|--packages/ //这里是寄存微服务各模块等目录,前面已更改为project,对应须要调整的配置见下方lerna.json▼|--package.json|--lerna.jsonumi-qiankun-explore/lerna.json { "packages": ["project/*"], "workspaces": ["project/*"], "version": "0.0.0"}umi-qiankun-explore/package.json { "name": "root", "private": true, "scripts": { "clone:all": "bash ./cli/clone-all.sh", // 这里用来能够依据设施写一个clone所有子项目的脚本 "boots": "lerna bootstrap --hoist", // 装置子项目所有公共的依赖 "start": "lerna run --parallel start " //启动所有子项目 }, "devDependencies": {}}这里批改目录次要是在命令行下切换目录p加Tab会把 package.json 也带进去,就不太不便 ...

August 6, 2021 · 2 min · jiezi

关于react.js:React更新流程简介

概述React创立的应用程序分两局部,一部分是首次创立的Mount阶段,另一部分是常见的更新更新和事件触发阶段Update阶段。对于DOM更新是两套流程,首次创立和DOM更新。简述React中Class组件生命周期的运行工夫点和HOOK组件中UseEffect、UseLayout的运行工夫点Render阶段Render阶段又分beginWork阶段和complete阶段Render阶段次要的目标是为每一个HTML节点生成Fibre节点,须要执行的事件也会挂载到Fibre节点上, 并依据页面构造生成Fibre链表Render阶段生成Fibre链表完结后,交给commit阶段。commit阶段会在此基础上执行事件、渲染或更新DOM,最初绘制到页面上。 beginWork阶段——创立Fibre节点在这个阶段会更依据页面的HTML构造和HTML元素生成创立对应的Fibre对象,记录节点的相干信息。如节点类型、节点上的属性、父级对象...在产生页面更新时,React会为每个元素从新构建一个新的Fibre对象。会在此阶段尝试复用上次的Fibre对象,如果没有产生扭转就间接复制过去。会在此阶段调用shouldComponentUpdate生命周期函数,若调用该函数,则react页面在视觉上不会产生更新,但ref的援用还是会产生更新。 complete阶段——创立虚构DOMbeginWork生成Fibre对象后,在Complete办法中生成虚构DOM。如果该Fibre节点有父级对象,则会将创立的虚构DOM挂载到父级Fibre的属性中当执行到最初一个节点时,会失去一个虚构DOM树,而后进入Commit阶段。 Fibre对象和虚构DOM的构建 Commit阶段React相干生命周期解决Render阶段的Fibre链表,执行事件或更新DOM。commit阶段分3局部,beforeMuation、Mutation、Layout。 beforeMutaion阶段解决focus事件对于Class组件而言,解决getDerivedStateFromProps生命周期函数,能够管制本次更新过程中,页面能不能产生扭转。对于HOOK而言,会将useEffect中的回调函数退出一个队列,会在整个Commit阶段实现当前再异步执行,而在本阶段并不会间接执行。调用Class组件的getSnapshotBeforeUpdate生命周期函数Mutation阶段Mutation阶段会遍历蕴含useEffecTarget属性t的Fibre链表,有须要文本更新的就更新,有须要更新ref的就更新ref。对DOM节点进行增删改查的操作。处理结果会反馈到Fibre节点中(如新增fibre节点,删除fiebr节点),这个Fibre节点并不一定是以后Fibre节点,也可能是以后Fibre节点的父级。对于以后Fibre节点产生更新的状况,若是HOOK组件,会调用useLayoutEffect的销毁函数;对于Class组件而言,会调用componentDidWillUnMount生命周期函数。如果以后Fibre节点类型不是HOOK或Class类型,如div类型、span类型...就不会执行销毁函数的回调。(PS:更新后的后果必须保障上一次的销毁函数调用)Mutation阶段的current指针还是之前的,所以执行销毁函数的回调没有问题。layout阶段layout阶段会替换current指针,这就是双缓存机制产生变更的工夫点。layout阶段会依据current指针是否有值,执行不同的生命周期函数。没有值,执行Class组件的componentDidMount生命周期;有值就执行componentDidUpdate生命周期函数。对于HOOK而言,会调用useEffect的回调函数,将销毁函数退出到队列中。本阶段的最初会查看这个队列,如果有的话会执行队列工作,直到清空后才算实现layout阶段。this.setState()的回掉函数,也就是第二个参数,也是在这个阶段执行。会执行useLayoutEffect的回调函数,并将新的销毁函数增加到一个队列中。再次更新时,Mutation阶段就会执行UseLayout的销毁函数。

August 6, 2021 · 1 min · jiezi

关于react.js:React中的memoized为什么不是memorized

当发现React.js中的memoized认为是拼写错误,然而本着小心求证的心态还是去百度翻译有道查了下词典。发现果然是拼写错了。 最初通过多番查找发现memoize是专门用于计算结果的存储。英文词典没有这个单词的收录。 As verbs the difference between memorize and memoize is that memorize is to learn by heart, commit to memory while memoize is (computing) to store (the result of a computed expression) so that it can be subsequently retrieved without repeating the computation.作为动词,memorize和memoize的区别在于,memorize是背诵,致力于熟记,而memoize(计算)是存储(计算表达式的后果),以便在不反复计算的状况下随后检索。

August 6, 2021 · 1 min · jiezi

关于react.js:React17-与React16-变化这些

新的JSX转换React 16原理babel-loader会预编译JSX为React.createElement(...) React 17原理React 17中的 JSX 转换不会将 JSX 转换为 React.createElement,而是主动从 React 的 package 中引入新的入口函数并调用。另外此次降级不会扭转 JSX 语法,旧的 JSX 转换也将持续工作。 总结React 17反对新的JSX转换。咱们还将对它反对到React 16.14.0,React 15.7.0和0.14.10。须要留神的是,这是齐全抉择启用的,您也不用应用它。之前的JSX转换的形式将持续存在,并且没有打算进行对其反对。 事件代理更改在React 17中,React将不再在后盾的文档级别附加事件处理程序。取而代之的是,它将它们附加到渲染您的React树的根DOM容器: const rootNode = document.getElementById('root');ReactDOM.render(<App />, rootNode); 总结在React 16和更早的版本中,React将对大多数事件执行document.addEventListener()。React 17将在后调用rootNode.addEventListener()。 渐进式降级React v17 开启了 React 渐进式降级的新篇章。当你从 React 15 降级至 16 时(或者,从 16 降级到 17),你通常会一次性降级整个应用程序,这对大部分利用来说非常无效。然而,如果代码库编写于几年前,并且没有及时的保护降级,这会使得降级老本越来越高。并且,在 React 17 之前,如果在同一个页面上应用不同的 React 版本(能够这么做,然而有危险),会导致事件问题的呈现,会有一些未知的危险。 咱们正在修复 React v17 中的许多问题。这意味着,当 React 18 或将来版本来长期,你将有更多抉择。首选,当然还是一次性降级整个利用;但你还有个可选计划,渐进式降级你的利用。举个例子,你可能将大部分性能降级至 React v18,但保留局部懒加载的对话框或子路由在 React v17。 但这并不意味着你必须进行渐进式降级。对于大多数利用来说,一次性降级仍是更好的抉择。加载两个版本的 React,依然不是现实计划 —— 即便其中一个版本是按需加载的。但对于那些长期未保护的大型利用来说,这意义不凡,React v17 开始让这些利用不会被轻易淘汰。 咱们筹备了示例仓库,此示例演示了如何在必要时懒加载旧版本的 React。此示例由 Create React App 构建,应用其余工具也能够实现同样的成果。欢送应用其余工具的小伙伴通过 PR 的模式提供 Demo。 ...

August 4, 2021 · 1 min · jiezi

关于react.js:项目踩坑记无法将createreactapp项识别为-cmdlet函数脚本文件或可运行程序的名称解决

创立我的项目的时候报错试过网上改淘宝镜像的法子不行最初应用npx 胜利了npx create-react-app todo-list npx 会主动查找以后依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果仍然找不到,就会帮你装置。 npx 甚至反对运行近程仓库的可执行文件。 npx解释:https://www.jianshu.com/p/684...

August 3, 2021 · 1 min · jiezi

关于react.js:react笔记

1.redux中间件的原理是什么 改装dispatch, 中间件(action和store之间 )。沟通的桥梁就是dispatch 失常状况action传递给store必须是个对象,然而用中间件能够帮忙把函数式的action转换成对象再传递给store 看一下redux-thunk的源码2.你会把数据对立放到redux中治理,还是把共享数据放在redux中治理? 所有数据:1.为了保障数据处理的一致性。2.当之前本人的数据变成专用数据就会很麻烦。联合immutable.js进行最佳体验的数据状态治理3.componentWillReceiveProps 的调用机会当props扭转的时候,第一次不会调用4.react性能优化的最佳实际PureComponent和immutable.js联合应用5.虚构dom是什么?为什么虚构dom会晋升代码性能js对象 。实在dom比对下面有各种属性,绑定事件,如果间接比对会十分消耗性能对于key?如果key值雷同,就能够复用之前的dom,也不必循环比对。diff算法就是,如果一层发现有问题,就不往下比了,同层比对,这样就升高了复杂度6.webpack中,是借助loader实现的jsx代码转换还是babel?1.babel-preset-react7.调用setState后,产生了什么?和谐。注:养成好的习惯改成函数式返回对象的模式。如何同步获取setState扭转后的属性?应用回调函数。切忌应用settimeout!8.setState是异步的,这个点你在什么时候遇到过坑9.refs的作用是什么,你在什么业务场景下应用过refs?“放大镜”,获取图片宽高10.ref是一个函数,有什么益处?无效的清空援用外面的货色,避免内存透露11.高阶组件你是怎么了解的,它实质是一个什么货色?实质是一个函数。高阶组件天堂怎么办?hooks12.受控组件和非受控组件数据管制dom;间接通过refs管制dom,脱离数据13.函数组件和hooks14.this指向问题你个别怎么解决箭头函数,bind15.函数组件怎么做性能优化React.memo把函数组件进行包裹16.哪个生命周期发送ajax?compoentDidMoutssr我的项目时,CompoentWillMount要做服务端数据的获取,所以不能被占用17.ssr的原理是什么?借助虚构DOM18.redux-saga的设计思维是什么?什么是sideEffects19.react,jquery,vue能够共存在一个我的项目吗?<div> <div><div id ='react'></div><div id = 'vue'></div>20.组件是什么?类是什么?类被编译成什么?组件是页面的一部分,类是一个构造函数21.你是如何跟着社区成长的?react官网团队的推特22.如何防止ajax数据从新获取redux治理23.react-router4 的核心思想是什么,和3有什么区别?组件式的路由思维24.reselect是做什么应用的?计算属性,25.hashHistory,browserHistorybrowserHistory须要后端一起配制,hashHistory齐全能够依赖前端26.什么状况下应用异步组件我的项目很大时reloadable 库路由懒加载,按需加载27.xss攻打在react如何防备?慎用dangerouslySetInnerHTML={{alert}}28.immutable.js和redux最佳实际

August 2, 2021 · 1 min · jiezi

关于react.js:React从入门到精通一

React简介React 是一个用于构建用户界面的 JS 库,次要用于构建UI。 React由美国的公司Facebook在2011年诞生并于2013年开源公布 特点:1.申明式设计 −React采纳申明范式,能够轻松形容利用。 2.高效应用虚构dom+优良的diffing算法,缩小了与实在dom的交互 3.JSX 是 JavaScript 语法的扩大。React 开发不肯定应用 JSX ,但咱们倡议应用它。 4.组件 − 通过 React 构建组件,使得代码更加容易失去复用,进步开发效率,可能很好的利用在大我的项目的开发中。 5.单向响应的数据流 − React 实现了单向响应的数据流,从而缩小了反复代码,这也是它为什么比传统数据绑定更简略 6.在React-Native中能够应用React语法进行挪动端开发 虚构dom其实虚构dom实质上是一个Object类型的个别对象 虚构dom的长处: 1.它加载过一次数据时就会把加载过的数据放到内存中下次如果有更改而后持续加载的时候只是加载新增的数据并不会去反复加载之前的数据 2.虚构dom绝对于实在dom是更轻量级的,因为虚构dom是react外部在用,用哪个提供哪个属性,无需实在dom上挂载的那么多属性 3.虚构dom会被React转换成实在dom最初渲染到页面上 MVM长处MVM模式和MVVC模式一样,次要目标是拆散视图(View)和模型(Model),有几大长处React框架只是mvc中的c,Angular才是真正的mvc框架 1. 低耦合:视图(View)能够独立于Model变动和扭转,一个ViewModel能够绑定到不同的’View’上,当View变动的时候Model能够不变,当Model变动的时候View也能够不变 2.可重用性:你能够把一些视图逻辑放在一个ViewModel外面,让一个ViewModel外面,让很多view重用这段视图逻辑 3.独立开发:开发人员能够专一于业务逻辑和数据的开发(ViewModel),设计人员能够专一于页面设计,应用Expression Blend能够很容易设计界面并生成xml代码 4.可测试:页面元素来是比拟难于测试的,而当初测试能够针对ViewModel来写。 react中共有俩种组件类型:class类组件 在 class 类组件中 React 元素的地位是在 render() 函数中,也就是说,类组件中必须有一个 render() 函数,在 render() 函数中必须有 return 的值,这个值必须是虚构 DOM(React 元素)。class View extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; }}export default View函数组件(其中蕴含react新个性hook) 组件名字首字母肯定是大写的函数组件又叫无状态组件,没有生命周期 (hook呈现后使得函数组件也有了本人的生命周期)函数组件只有当展现视图的时候才用。做简单的数据处理、须要有本人的状态的时候,须要用类组件。function View(props) { return <h1>Hello, {props.name}</h1>;}俩大组件总结: ...

August 2, 2021 · 1 min · jiezi

关于react.js:React-源码解析系列-React-的-render-阶段一基本流程介绍

React 的工作流程React 的工作流程次要分为 render 和 commit 两个阶段: render 阶段依据 JSX 转化成的 ReactElement (更精确地来说,jsx 经 babel 转化后是 React.createElement() 的代码段,在 render 阶段该代码段被执行后便生成了对应的 ReactElement 对象)来创立 Fiber 树;React 采纳“双缓存”的思维,因而同一时刻维持有两棵 Fiber 树 ,一颗是 current,对应浏览器以后已渲染的 DOM 树,而另一棵则是 workInProgress,是在初始化时或者组件状态更新后由 reconciler 创立的一个工作正本。commit 阶段指的是把 workInProgress 渲染到页面上 ,当然这个过程并不会是全量更新,而是依据创立 workInProgress 时打的一些“标记”(effectTag),来确定在某个 DOM 节点上具体做什么操作,比方更新文本、删除节点等,以尽量小的代价来在 DOM 上还原 workInProgress ;workInProgress 会在 commit 后被置为 current。render 阶段的入口render 阶段开始于 performSyncWorkOnRoot 或 performConcurrentWorkOnRoot 办法的调用,这两个办法的差别在于一个是同步,而另一个是异步(concurrent)的。 这两个办法别离会调用上面两个办法—— workLoopSync 和 workLoopConcurrent: function workLoopSync() { // Already timed out, so perform work without checking if we need to yield. while (workInProgress !== null) { performUnitOfWork(workInProgress); }}function workLoopConcurrent() { // Perform work until Scheduler asks us to yield while (workInProgress !== null && !shouldYield()) { performUnitOfWork(workInProgress); }}这两个办法的差异在于是否调用 shouldYield() 来判断以后浏览器帧有没有空余工夫,对于 concurrent 模式来说,如果没有空余工夫就会退出以后循环了;能够看到这两个办法最终都调用了 performUnitOfWork 。 ...

August 1, 2021 · 2 min · jiezi

关于react.js:浅谈React-高阶组件

前文5、6月始终忙着本人的琐事,7月(7月31也还是7月嘛)抽空整顿一下旧的内容,有之前的读者提到想理解下高阶组件这块的知识点,就刚好整顿了一下。 高阶组件 HOC(HigherOrderComponent) ,听起来像是个一个 React 的高级性能,然而实际上它不属于 React API ,而应该归为一个是应用技巧或者说设计模式。首先直击实质: 高阶组件是一个函数, 并且是一个“参数为组件,返回值为新组件的”的函数。更直白一点如下: Fn(组件) => 有更强性能地新组件这里的Fn 就是高阶组件。 组件是 React 中的一个根本单元,通常它承受一些 props 属性,并最终展现为具体的UI,然而某些场景下传统组件还不足以解决问题。 在此分割线下 ,咱们能够临时抛开干燥的代码,聊一聊生存中一个常见的场景 - 点奶茶。在当下生存里,奶茶成为很多人生存中的高兴调剂(毕竟生存曾经这么苦了-_-),而种类口味也是多种多样的,比如说根底的分类就有纯茶、奶茶、咖啡、鲜榨果汁等,加料也是形形色色,有芝士,牛乳、干果碎,芋泥等.... (嗯 我筹备先点一杯奶茶,喝完回来持续写) 好的,我回来了~ 那么当初就能够形象出几个根底组件: 纯茶奶茶果茶它们别离都可搭配以下加料: 加芝士加碧根果碎对于不同根底茶加料的逻辑行为,是类似的,所以这两种加料形式就能够设计为高阶组件,这样能够很不便地依据须要生成不同类型地最终奶茶。套用后面地函数表达式也就是: Fn(根底奶茶) => 不同风味的奶茶这里的Fn也就是加料函数。它的作用是让一款根本的奶茶通过加料变成一款加强的奶茶。 注释到此,置信大家对高阶函数的作用有个大略的概念了, 接下来进入正题(醒醒 干燥的来了)。 从一个常见场景说起置信前端同学都写过不少后盾零碎,天然免不了某些常见性能,比方操作日志打印,权限管制等,以操作日志打印为例,要实现以下需要:在进入某些页面组件时,须要打印出日志并传送至服务器。 class Page1 extends React.Component { componentDidMount() { // 用console.log来模仿日志打印 实际上这里个别会传到服务器保留 console.log('进入page1'); } render(){ return <div>page1</div> }}class Page2 extends React.Component { componentDidMount() { console.log('进入page2'); } render(){ return <div>page2</div> }}察看这 Page1 Page2 两种组件都存在一部分类似的逻辑:在 componentDidMount 阶段,须要console.log 以后的页面名称。 ...

July 31, 2021 · 3 min · jiezi

关于react.js:新加坡-GONGHAOFINTECH-招聘-JAVA前端后端开发-WEB前端工程师-高级运维-30K起步上不封顶

▪️ Feature for comapny:我們公司位於新加坡。有寰球領先的金融交易平台,同時運營著整個金融生態體系。寰球共3000位員工,旗下有期貨、股票交易平台,為金融行業的投資者提供專業、數據驅動的見解和剖析報告, 寰球大型區塊鏈驅動的慈悲基金會之一,利用區塊鏈技術提供的透明化、高效率和問責制來从新定義慈悲公益事業。共好區塊鏈項目是一個為寰球優質區塊鏈項目提供代幣的發行的平台。JAVA▪️ Job Content:1、深刻开掘和剖析數字流動業務需要,編寫技術计划和系統設計;2、參與技術计划和系統設計驗證;考慮到系統的設計,確保系統的質量;3、系統外围局部代碼寫;疑難問題的解決;4、跨團隊,部門推進外围項目,跟進項目推進項目落地,並關注項目數據及結果;5、對未來或未來系統進行宏觀的思考,規劃統一造成的框架、平台或組件;6、指導和培訓工程師,幫助團隊成員独特成就;7、為團隊引入創新的技術、創新的解決计划,用創新的思路解決問題;通過企業不斷地優化系統,晋升產品體驗。 ▪️ Requirment1、擁有幣交所經驗,入幣交易、幣幣交易,對交易邏輯有粗浅的認知;2、JAVA基礎扎實:仔細把握數據結構、多線程編程,把握罕用的設計模式;瞭解JVM,包含內存模型、加載類機制以及性能優化;3、精通Web,5年及以上应用Java語言進行web開發的經驗,精通spring mvc、orm框架(ibatis或hibernate),知識編程前端開發(js、html、css);4、精通微服務架構,如springcloud;5、系統經驗豐富,能處理十萬單的順利;6、有良好的產品思維,能夠站在產品的角度下思考問題、產品的技術綜述;有複雜領域建模經驗;7、具备高度的形象設計能力,思路清晰,长于思考,責任獨立剖析和解決問題,心能強;具備良好的團隊单干精力和風險預判能力,對系統的壓力和路徑優化和解決计划落地;8、有本人的方向對發展的方向;能夠十分清晰地規劃出業務和技術方向,並能夠階段性落地,获得成绩。9.有數字貨幣交易開發或股票、外匯、數字經驗、創業等行情開發10.瞭解和置信智能貨幣的,应用過至多二間產生的產品並進行過未來的知識交易領先胜利 【WEB前端JD】 1、依据需要,独立实现页面开发,和逻辑实现2、负责产品模块的bug修复3、关注性能,晋升客户端用户体验 要求:1、大专及以上学历,3年以上前端工作教训;2、技术全面,对html,css,js,http有较好把握;纯熟解决各种浏览器兼容问题;3、熟练掌握Web前端框架React等,有理论的我的项目教训;4、相熟各种前端开发和测试工具(Firebug, Fiddler, Postman, Web developer tools等);5、良好的逻辑编程能力,具备规范化,标准化的代码编写习惯;6、工作积极主动有责任心;【運維】 **有帶領團隊經驗 职位职责:1.负责线上及测试服务器的架构及部署工作,保障线上环境的稳固;2.负责公司各服务器集群的部署、治理和监控;3.日常运维操作,负责线上服务器的公布,服务器监控、问题排查及应急解决等工作,软硬件运行监控,服务器自动化脚本开发;4.负责运维局部外部技术文档和业务文档记录和输入;5.联合本身工作,发展运维自动化的钻研与利用。 职位要求:1.大专及以上学历;2.领有四年以上的Linux零碎的运维治理,具备企业级大规模零碎的运维能力;3.纯熟根底服务(Nginx、k8s、docker、rockectmq、Jenkins、ansible、zabbix)的企业级生产环境的搭建、配置与调优工作;4.存储相干服务组件装置和应用教训(redis,mongdb,elk,mysql)5.相熟ITIL运维管理体系;6.沟通、执行力强,团队合作能力强 ;7.理解和置信加密货币的将来,应用过至多二间交易所产品并曾进行过加密货币交易优先录取8.有治理海内分部教训优先,有率领团队部署治理教训联系方式:NASH CHEN Manager | Gonghaofintech Co. 地址: 316 SEMBAWANG VISTA #03-185 SINGAPORE, Singapore, SG邮箱: skyk888skyk@gmail.comQQ:1435295631微信: EUROVIP

July 31, 2021 · 1 min · jiezi

关于react.js:基于React脚手架搭建React-dvatypescript-webpack-less

基于React脚手架搭建React + dva + webpack + lessMac react-create-app 创立react我的项目及typescript,react-create-app须要本人装置配置,不赘述npx create-react-app [app0729-自定义文件名] --typescript执行yarn start 能够看到默认页面了~裸露webpack,即生成webpack配置等文件, config/scriptyarn eject装置dvayarn add dva配置路由yarn add history src下创立routes文件夹,该文件夹内放各个页面,每个页面独自创立文件夹举个栗子~ // home.tsximport { Link } from 'dva/router';import React from 'react';const Home = ({history}: any): JSX.Element => { return ( <div className="home-wrapper"> <h1>home</h1> <p onClick={() => { // history跳转 history.push('/orderList'); } }>去订单列表页</p> // link标签跳转 <Link to={'/orderList'}>去订单列表页</Link> </div> )}export default React.memo(Home);批改src/app.tsx文件 -- 管制路由import React from 'react'; import { Router, Route, Switch } from 'dva/router';import dynamic from 'dva/dynamic';const routes = [ { key:'home', path: '/', component: () => import('./routes/Home/home'), }, { key:'/orderList', path: '/orderList', component: () => import('./routes/Order/orderList/index'), }, { key:'/orderDetail', path: '/orderDetail', component: () => import('./routes/Order/orderDetail/index'), }];function RouterConfig({ history, app }: any) { return ( <Router history={history}> <Switch> { routes.map((item: any): any => ( <Route key={item.key} path={item.path} exact // @ts-ignore component={dynamic({ // @ts-ignore app, models: item.models, component: item.component, })} /> )) } </Switch> </Router> ); } export default RouterConfig; 批改src/index.tsx文件 入口文件import dva from 'dva'; // import './index.css'; import { createBrowserHistory } from 'history'; // 1. Initialize const app = dva({ history:createBrowserHistory()}); // 2. Plugins -- 能够挂载loading等插件// app.use({}); // 3. Model -- 引入全局model 可稍后尝试// app.model(require('./models/app').default); // 4. Router app.router(require('./App.tsx').default); // 5. Start -- 挂载到 #root DOM上app.start('#root'); 执行yarn start曾经能够看到页面内容了,能够点击跳转页面~ ...

July 29, 2021 · 2 min · jiezi

关于react.js:React学习笔记

1:在React中有一个命名标准,通常会将代表事件的监听prop命名为 on[Event] 将处理事件的监听办法命名为 handle[Event] 这样的格局 2:React DOM 应用camelCase小驼峰命名来定义属性的名称, 例如,JSX 里的 class 变成了 className,而 tabindex 则变为 tabIndex。 3:React Dom 会将元素和他的子元素与他们之前的状态进行比拟,只更新他须要更新的局部。React DOM 只会更新理论扭转了的内容。 4:函数组件:function Square(props) { return ( <button className="square" onClick={props.onClick}> {props.value} </button> );}你同时还能够应用 ES6 的 class 来定义组件:class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; }}// 留神: 组件名称必须以大写字母结尾。React 会将以小写字母结尾的组件//视为原生 DOM 标签。例如,<div /> 代表 HTML 的 div 标签,而 <Square /> //则代表一个组件,并且需在作用域内应用 Square。5: Props 的只读性 所有 React 组件都必须像纯函数一样爱护它们的 props 不被更改。 6: State的更新可能是异步的 ...

July 28, 2021 · 2 min · jiezi

关于react.js:react排序组件ReactSortablehoc

可实现程度、垂直拖拽排序的react库Githubhttps://github.com/clauderic/react-sortable-hoc官网demodemo 装置npm install react-sortable-hoc --save根本应用import React, {Component} from 'react';import {render} from 'react-dom';import {SortableContainer, SortableElement} from 'react-sortable-hoc';import arrayMove from 'array-move';const SortableItem = SortableElement(({value}) => <li>{value}</li>);const SortableList = SortableContainer(({items}) => { return ( <ul> {items.map((value, index) => ( <SortableItem key={`item-${value}`} index={index} value={value} /> ))} </ul> );});class SortableComponent extends Component { state = { items: ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6'], }; onSortEnd = ({oldIndex, newIndex}) => { this.setState(({items}) => ({ items: arrayMove(items, oldIndex, newIndex), })); }; render() { return <SortableList items={this.state.items} onSortEnd={this.onSortEnd} />; }}render(<SortableComponent />, document.getElementById('root'));

July 22, 2021 · 1 min · jiezi

关于react.js:React大型项目状态管理库如何选型

背景因为要做一个应用起来比拟难受的轮子,最近钻研了下React的状态治理库,当然,仅限在应用层面,也就是用着难受的角度来抉择到底应用哪个状态治理库。本着在Github下面看看React社区内状态治理库的风行水平和应用水平的层面,来进行选型,而后就有了这篇文章,对于咱们最初抉择了哪个,文章开端告知。 抉择库的准则如下: 全面拥抱typescript,so抉择的库须要对typescript反对敌对react自从16.8引入hooks,接下来就开始了函数式编程的时代,所以不要有class这玩意肯定要应用简略,不要太简单,应用起来很轻量,重点是难受反对模块化,能够集中管理,原子性低反对esmodule,因为前面会思考迁徙到vite,尽管当初还是webpack截止目前为止,在Github下面看了一下以后比拟风行的几个状态治理库的star数和used by的数量,以及npm下面的周下载量(weekly downloads),这能够从某些方面说明明该框架的受欢迎水平,也有很小的可能性不精确,不过很大水平上,对框架选型是有所帮忙的。 库名github stargithub usednpm 周下载量mobx23.9k83.9k671,787redux-toolkit5.9k83.2k755,564recoil13.5k83.9k95,245zustand9.4k7.2k104,682rematch7.3k2.5k33,810concent950651,263下面表格中,就是咱们接下来要进行筛选的对象,到底中意哪个,还得看看应用起来的时候的姿态,哪个更加难受。 mobxmobx是一个十分优良的react状态治理库,这毋容置疑,而且在Github下面,它的使用量也是做到了第一,官网文档地址zh.mobx.js.org。官网下面给的例子是非常简单的,大多数官网也都如此,可是我不须要简略的例子,我须要一个残缺的我的项目的例子,于是参考了github下面的一个我的项目antd-pro-mobx。mobx须要搭配mobx-react的连贯库一起来应用。 依照npm下面的举荐是要应用class + observe函数包裹的形式,最新版本v6: import React from "react"import ReactDOM from "react-dom"import { makeAutoObservable } from "mobx"import { observer } from "mobx-react"// Model the application state.class Timer { secondsPassed = 0 constructor() { makeAutoObservable(this) } increase() { this.secondsPassed += 1 } reset() { this.secondsPassed = 0 }}const myTimer = new Timer()// Build a "user interface" that uses the observable state.const TimerView = observer(({ timer }) => ( <button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>))ReactDOM.render(<TimerView timer={myTimer} />, document.body)// Update the 'Seconds passed: X' text every second.setInterval(() => { myTimer.increase()}, 1000)新我的项目的从头开始,应该不会抉择老版本的库区应用,个别会抉择稳固的新版本的进行应用,对于typescript方面,看源码是曾经在应用typescript来编写了,不过在官网和npm下面并没有看到typescript的蛛丝马迹,可能是还没发版吧。 ...

July 20, 2021 · 5 min · jiezi

关于react.js:一个异想天开的个人工作台基于-react-electron

<div align=center> <img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fb36dbbda50840feb4c45a270f0d3c63~tplv-k3u1fbpfcp-watermark.image" width="400px" /></div> 源码地址请撮 这里公众号请搜寻:小宇的技术随笔 基于 vscode 架构,利用 【依赖注入】【多过程】等思维实现的工具集 工具汇合[ ] 插件化 markdown 文件性能[x] 搜寻[x] 文件治理(保留,重命名,新建)[x] 纲要预览模式[ ] 导出 pdf,md,html[ ] 导入 pdf,md,html转换成微信公众号[x] 默认主题[ ] 主题定制[ ] 图片排版[ ] 一键公布代理工具[ ] ...开发装置依赖设置electron镜像 yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/装置依赖 yarn开发yarn start:viewsyarn start:workbench打包成 mac:yarn release:mac

July 16, 2021 · 1 min · jiezi

关于react.js:reactrouterdom

1、装置yarn add react-router-dom2、根本应用BrowserRouter,HashRouter是两种路由形式,应用NavLink ,Link,Route时必须被路由器包裹。NavLink ,Link是设置页面跳转,而NavLink有activeClassName属性,能够自定义设置active选中的class,默认activeClassName="active"。import { BrowserRouter,HashRouter,NavLink ,Link,Route} from "react-router-dom"import Home from './components/Home'import About from './components/About'<BrowserRouter> <NavLink activeClassName="demo" className="list-group-item" to="/about"> About </NavLink> <NavLink activeClassName="demo" className="list-group-item" to="/home"> Home </NavLink> <Route path="/about" component={About}></Route> <Route path="/home" component={Home}></Route></BrowserRouter>扩大

July 15, 2021 · 1 min · jiezi

关于react.js:React-向路由组件传递参数

咱们罕用的传递参数形式为三种,通过例子展现一下三种办法是如何应用的: 传递参数的组件 import React, { Component } from 'react'import { Switch,Route,Link } from 'react-router-dom'import Detail from './Detail'export default class Message extends Component { state ={ messageArr :[ {id:'01',title:'音讯1'}, {id:'02',title:'音讯2'}, {id:'03',title:'音讯3'} ] } render() { const {messageArr} = this.state return ( <div> <ul> { messageArr.map((msgObj) =>{ return ( <li key={msgObj.id}> {/* 向路由组件传递 params 参数 */} {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> */} {/* 向路由组件传递 search 参数 */} {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link> */} {/* 向路由组件传递 state 参数 */} <Link to={{pathname:'/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link> </li> ) }) } </ul> <hr/> {/* 注册路由*/} <Switch> {/* 申明接管 params */} {/* <Route path='/home/message/detail/:id/:title' component={Detail}></Route> */} {/* search 参数无需申明接管 */} {/* <Route path='/home/message/detail' component={Detail}></Route> */} {/* state 参数无需申明接管 */} <Route path='/home/message/detail' component={Detail}></Route> </Switch> </div> ) }}接管参数的组件 ...

July 14, 2021 · 1 min · jiezi

关于react.js:React-向路由组件传递-params-参数

传递参数组件的jsx文件: import React, { Component } from 'react'import { Switch,Route,Link } from 'react-router-dom'import Detail from './Detail'export default class Message extends Component { state ={ messageArr :[ {id:'01',title:'音讯1'}, {id:'02',title:'音讯2'}, {id:'03',title:'音讯3'} ] } render() { const {messageArr} = this.state return ( <div> <ul> { messageArr.map((msgObj) =>{ return ( <li key={msgObj.id}> {/* 向路由组件传递 params 参数 */} <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link> </li> ) }) } </ul> <hr/> {/* 注册路由 申明接管 params*/} <Switch> <Route path='/home/message/detail/:id/:title' component={Detail}></Route> </Switch> </div> ) }}接管参数组件的jsx文件: ...

July 14, 2021 · 1 min · jiezi

关于react.js:React-脚手架配置代理

办法一在package.json中追加如下配置 "proxy":"http://localhost:5000"阐明: 长处:配置简略,前端申请资源时能够不加任何前缀。毛病:不能配置多个代理。工作形式:上述形式配置代理,当申请了3000不存在的资源时,那么该申请会转发给5000 (优先匹配前端资源)办法二1、第一步:创立代理配置文件 在src下创立配置文件:src/setupProxy.js2、编写setupProxy.js配置具体代理规定: const proxy = require('http-proxy-middleware')module.exports = function(app) { app.use( proxy('/api1', { //api1是须要转发的申请(所有带有/api1前缀的申请都会转发给5000) target: 'http://localhost:5000', //配置转发指标地址(能返回数据的服务器地址) changeOrigin: true, //管制服务器接管到的申请头中host字段的值 /* changeOrigin设置为true时,服务器收到的申请头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的申请头中的host为:localhost:3000 changeOrigin默认值为false,但咱们个别将changeOrigin值设为true */ pathRewrite: {'^/api1': ''} //去除申请前缀,保障交给后盾服务器的是失常申请地址(必须配置) }), proxy('/api2', { target: 'http://localhost:5001', changeOrigin: true, pathRewrite: {'^/api2': ''} }) )}阐明: 长处:能够配置多个代理,能够灵便的管制申请是否走代理。毛病:配置繁琐,前端申请资源时必须加前缀。

July 13, 2021 · 1 min · jiezi

关于react.js:如何设计实现H5营销页面搭建系统

背景近几年,low code、no code、pro code等越来越多的呈现在咱们的视线中。抱着不被卷的心态 ,我决定来深刻摸索一下。 我所在的是营销部门。每天/月都承载着大量的营销流动,本文也是我在摸索可视化搭建过程中的一些心得体会其实这些名词都与搭建相干。其中一个利用最广的场景就是营销。咱们晓得无论是淘宝、京东这些电商巨头,亦或是携程、去哪儿这些OTA,每天 APP 上都承接着有数的流动页面。 大抵梳理一下营销流动的一些特点: 页面相似: 页面布局和业务逻辑较固定需要高频: 每周甚至每天有多个这种需要迭代疾速: 开发工夫短, 上线工夫紧开发耗时: 开发工作反复, 耗费各方的沟通工夫和人力不同于惯例的业务开发,营销流动往往受影响的因素很多:节假日大促、政策规定等,所以往往可能是今天上午说的流动,今天就要上这种。如果单靠前端同学去保护,那怕不是要加有数的班(比方之前的我 ) 每次来一个新流动,都靠前端同学去画页面,显然这种效率是极低的。如果排期拮据点还行,如果遇到618、双11怕不是要逼疯咱们。。 楼层搭建 鉴于这种场景,外部也进行了很多的探讨。得出的统一论断就是:开发同学提供营销搭建后盾,页面做成可配置化,配置的工作交给产品/经营同学。这样,基于楼层搭建营销页面的计划就应运而生了。 其实楼层搭建在营销页面的搭建中是一种比拟常见的形式。如上图是京东的一个流动页面,页面次要由三局部组成:头图楼层、优惠卷楼层、热销楼层。因为就像生存中的盖楼一样,所以在晚期的营销搭建中,就有了楼层的概念。每个楼层其实就对应了一个具体的组件。而后在具体楼层的编辑内容区域就能够去上传对应的数据了。 但这种形式有一个很大的毛病就是:不够直观。随着业务的疾速迭代,也陆续失去了一些反馈。最终发现经营同学真正须要的是那种能够间接拖拽生成页面的,也就是可视化搭建 可视化搭建 在楼层搭建的根底上进一步革新为可视化搭建,复杂度晋升了很多。单纯的去看页面的不同出现,可能仅仅就是加了一个拖拽的操作。但真正筹备去落地的时候,发现其中的细节特地多,也蕴含了很多的设计理念在外面。 咱们先来看一下原型图,而后仔细分析一下须要做的事件:市面上大部分营销可视化搭建零碎根本都是相似上图这样的页面出现。左侧对应组件区域,两头是画布区域,右侧是属性区域。 大抵操作流程就是拖动左侧的组件到两头的画布,选中组件,右侧属性面板就会展现与该组件关联的属性。编辑右侧属性,画布中对应的组件款式就会同步更新。页面拼接实现,可通过相似预览的操作进行页面预览。预览无误,即可通过公布按钮进行流动的公布。 流程梳理完,咱们来看下我的项目的基础架构: 这里我基于原型对我的项目设计进行了性能的铺平,其实还是围绕组件、画布、属性面板这三块。 到这里,咱们思考几个问题: 画布区域如何渲染已增加到画布中的组件(组件库组件会很多,画布中可能只需增加几个组件,思考如何做动静渲染)?组件从左侧拖入画布区域,选中组件,就可晓得该组件关联的属性。组件 Schema 如何设计?画布区域和预览时组件的渲染是否可共用一套渲染逻辑?组件的数据如何去保护(思考增加组件、删除组件、组件渲染/预览等场景)组件库如何保护(思考新增组件满足业务须要的场景)首先来看第一条,简略演绎就是动静加载组件。 动静加载组件 如果你常常应用vue,那我想你对vue中的动静组件必定不生疏: <!-- 当 currentView 扭转时组件就扭转 --><component :is="currentView"></component>市面上的大部分编辑器也都是利用了这个个性,大抵实现思路就是: 用一个数组componentData保护编辑器中的数据将组件拖动到画布中时,将此组件的数据push进componentData编辑器遍历(v-for)组件数据componentData,将组件顺次渲染到画布中因为我在的团队包含我本人始终都在应用react,这里着重来提下react组件动静加载的实现形式,框架应用的是umi。 我在实现这部分性能时,在umi的api中找到了dynamic:封装一个异步组件: const DynamicComponent = (type, componentsType) => { return dynamic({ loader: async function () { const { default: Component } = await import( `@/libs/${componentsType}/${type}` ); return (props) => { return <Component {...props} />; }; }, });};而后在调用的时候,将组件数组传入即可: ...

July 13, 2021 · 3 min · jiezi

关于react.js:React-并发功能体验前端的并发模式已经到来

React 是一个开源 JavaScript 库,开发人员应用它来创立基于 Web 和挪动的应用程序,并且反对构建交互式用户界面和 UI 组件。React 是由 Facebook 软件工程师 Jordan Walke 创立,React 的第一个版本在七年前问世,当初,Facebook 负责保护。React框架自首次公布以来,React 的受欢迎水平直线飙升,热度不减。2020 年 10 月,React 17 公布了,但令人诧异的是——“零新性能”。当然,这并不是真的示意没有任何新增加的性能,让宽广程序员使用者兴奋。事实上,这个版本为咱们带来了很多重大性能的降级及16版本的bug修复,并推出了:Concurrent Mode 和Suspense。尽管这两个性能尚未正式公布,这些性能已提供给开发人员进行测试。一旦公布,它们将扭转 React 出现其 UI 的形式,从而达到双倍进步性能和用户体验。简要阐明, Concurrent Mode 和Suspense 能够使用户无缝解决数据加载,加载状态,用户界面操作更加平滑和无缝切换。 在Concurrent Mode 下,React能够暂停高耗费的,非紧急的组件的渲染,并聚焦在更加紧迫的工作解决,如UI 渲染,始终保持利用为可响应式,防止白屏,卡顿等景象。本文次要分享深刻理解Concurrent Mode 和Suspense 模式下的数据提取性能。 为什么须要 Concurrent Mode?家喻户晓,JavaScript 框架或库是单线程的工作。因而,当一个代码块运行时,其余的块必须期待执行。无奈并发执行多线程工作。界面渲染也是一样的。一旦 React 开始渲染某些货色,无奈中断直到运行实现。React 开发人员将这种渲染称为“阻塞渲染”。 这种阻塞渲染会创立一个不稳固的用户界面,并且随时可能进行响应。 具体问题如果,咱们须要显示一个很长的可选列表用于过滤产品的应用程序。咱们应用搜寻框用于过滤记录,设计方案是当用户点击搜寻按钮后,用户界面须要从新刷新列出相关联的数据。如果列表过长,数据过多,UI“卡顿”,即渲染对用户可见。这种卡顿也会大大降低产品性能。开发人员能够应用一些技术,如节流和防抖,这些技术会有肯定帮忙,但不是完满的解决方案。节流限度特定函数被调用的次数。应用节流,咱们能够防止反复调用低廉和耗时的API或函数。这个过程可能进步性能,尤其是在用户界面上出现信息。防抖会在预约的工夫内疏忽对函数的调用。函数调用仅在通过预约工夫后进行。下图形容了卡顿景象:在期待非紧急 API 调用实现时,UI 卡顿,从而阻止出现用户界面。解决方案是应用并发模式进行可中断渲染。 无中断渲染通过可中断渲染,React.js 在解决和从新渲染列表时不会阻塞 UI。它通过暂停琐碎的工作、更新 DOM 并确保 UI 不会卡顿,使 React.js 更加细化。React 应用用户输出并行更新或重绘输入框。React 应用用户输出并重绘输入框并行执行。它还更新内存中的列表。React 实现更新后,它会更新 DOM 并在用户的显示器上从新出现列表。实质上,无中断渲染使 React 可能“多任务”。此性能提供了更晦涩的 UI 体验。 ...

July 13, 2021 · 3 min · jiezi

关于react.js:useReducer-useContext-createContext

失常的 Increment 和 Decrement扭转 Display 的 countimport React, { useState } from 'react'function Display(props) { return <h1>Counter value : {props.counter}</h1>}function Increment(props) { return <button onClick={() => props.addToCounter(1)}>Increment</button>}function Decrement(props) { return <button onClick={() => props.addToCounter(-1)}>Decrement</button>}function Index() { const [counter, setCounter] = useState(0); const addToCounter = value => setCounter(counter + value); return ( <div> <h1>Teste</h1> <Display counter={counter} /> <Increment addToCounter={addToCounter} /> <Decrement addToCounter={addToCounter} /> </div> )}export default Index一步一步来改装应用useContext来替换Display组件中的props import React, { useState, useContext, createContext } from 'react'const CounterContext = createContext({counter: 0})function Display(props) {const context = useContext(CounterContext)return <h1>Counter value : {context.counter}</h1>}编写reducer去代替组件中的addToCounter办法 ...

July 11, 2021 · 2 min · jiezi

关于react.js:前端面试每日-31-第817天

明天的知识点 (2021.07.11) —— 第817天 (我也要出题)[html] 应用HTML5绘制一只卡通版米老鼠[css] 应用css3实绘制3D骰子多角度翻转特效[js] 写一个办法计算只有加法和乘法的表达式,如:2+3*9+6[软技能] 你会常常进来游览吗?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!! 欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨! 心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

July 11, 2021 · 1 min · jiezi

关于react.js:轻量且高性能的-React-状态管理库-Jotai

Jotai 是什么?Primitive and flexible state management for React援用官网原话,Jotai 是一个原始且灵便的 React 状态治理库 原始:API 都是以 Hooks 形式提供,应用形式相似于 useState,useReducer灵便:能够组合多个 Atom 来创立新的 Atom,并且反对异步同时,我认为 Jotai 称得上是一个玲珑、简洁且高性能的状态治理库 Jotai 能够看作是 Recoil 的简化版,应用了 Atom + Hook + Context,用于解决 React 全局数据流治理的问题 Atom 是 Jotai 中状态治理单位,它是能够更新和订阅的,当 Atom 被更新时,订阅了这个 Atom 的组件便会应用新值从新渲染 并且,更新对应的 Atom 只会从新渲染订阅了这个 Atom 的组件,并不会像 Context 那样导致整个父组件从新渲染,所以能够做到准确渲染 Jotai 与 Recoil 有何不同?Jotai 和 Recoil 概念很类似,都是采纳扩散治理原子状态的设计模式 所以在用法上也比拟类似,但相比之下,还有以下长处 Jotai 的 API 绝对 Recoil 简洁很多,并且容易应用Jotai 不须要用 RecoilRoot 或 Provider 等组件包裹,使得构造能够更简洁Jotai 定义 Atom 时不必提供keyJotai 更玲珑,大小仅 2.4 kBJotai 对 TypeScript 的反对更好如何应用 Jotai ?装置 Jotainpm install jotai定义 Atom一个 Atom 代表一个状态 ...

July 5, 2021 · 2 min · jiezi

关于react.js:React-TS-封装密码强度组件

在antd的Progress的根底上封装PwdStrength.tsx import { Col, Progress, Row } from 'antd';import { FC } from 'react';import styles from './index.less';interface IPwdStrengthProps { pwdStrength: 0 | 1 | 2 | 3;}const PwdStrength: FC<IPwdStrengthProps> = ({ pwdStrength }) => { return ( <div className={styles.passwordStrongBox}> <Row gutter={12}> <span className={styles.passWord}>明码强度</span> <Col span={3}> <Progress className={styles.weak} percent={pwdStrength > 0 ? 100 : 0} showInfo={false} /> </Col> <Col span={3}> <Progress className={styles.middle} percent={pwdStrength > 1 ? 100 : 0} showInfo={false} /> </Col> <Col span={3}> <Progress className={styles.strong} percent={pwdStrength > 2 ? 100 : 0} showInfo={false} /> </Col> <span className="passStrong"> {pwdStrength === 1 && '弱'} {pwdStrength === 2 && '中'} {pwdStrength === 3 && '强'} </span> </Row> </div> );};export default PwdStrength;笼罩原有款式,依据强度各个进度显式不同色彩,款式献上index.less ...

July 3, 2021 · 2 min · jiezi

关于react.js:前端面试每日-31-第809天

明天的知识点 (2021.07.03) —— 第809天 (我也要出题)[html] 应用HTML5制作一些微信罕用的表情包[css] 应用CSS3实现萤火虫发光动画成果[js] 如何定义一个防篡改对象?[软技能] 你能承受同一个岗位新来的共事工资给你高吗?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!! 欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨! 心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

July 3, 2021 · 1 min · jiezi

关于react.js:SolidJS硬气的说我比React还react

大家好,我是卡颂。 最近刷推时,有个老哥经常出现在前端框架相干推文下。 我想:“老哥你哪位?” 一查,原来是个框架作者,作品叫SolidJS。 翻翻框架介绍,这句话胜利吸引我的留神: 反对古代前端个性,例如:JSX, Fragments, Context, Portals, Suspense, Streaming SSR, Progressive Hydration, Error Boundaries和Concurrent Rendering我推敲您不会是React在逃公主吧?这不能说和React相似,只能说齐全一样吧? 作为传统中国人,秉承来都来了思维,我试用了一天,又看了下源码,后果发现这个框架真是个宝藏框架。 本文会比拟SolidJS与React的异同,论述他的独特劣势,看完后不晓得你会不会和我收回同样的感叹: 这几乎比React还react(react译为响应)置信看完本文后,不仅能意识一个新框架,还能对React有更深的意识。 开整! 初看很类似让咱们从一个计数器的例子看看与React语法的差别: import { render } from "solid-js/web";import { createSignal } from "solid-js";function Counter() { const [count, setCount] = createSignal(0); const increment = () => setCount(count() + 1); return ( <button type="button" onClick={increment}> {count()} </button> );}render(() => <Counter />, document.getElementById("app"));和React不同的中央: useState改名成createSignal获取count状态从React中间接应用count变为通过办法调用,即:count()难道仅仅是一个类React框架? 别急,让咱们从编译时、运行时、响应原理三方面来看看。 编译时大不同React的编译时很薄,根本只是编译JSX语法。 而SolidJS则采纳了相似Svelte的计划:在编译时,将状态更新编译为独立的DOM操作方法。 这样做有什么益处?次要有两点。 肯定条件下的体积劣势你不须要为你没应用的代码付出代价应用React时,即便没有用到Hooks,其代码也会呈现在最终编译后的代码中。 ...

July 1, 2021 · 1 min · jiezi

关于react.js:React-并发功能体验前端的并发模式已经到来

React 是一个开源 JavaScript 库,开发人员应用它来创立基于 Web 和挪动的应用程序,并且反对构建交互式用户界面和 UI 组件。React 是由 Facebook 软件工程师 Jordan Walke 创立,React 的第一个版本在七年前问世,当初,Facebook 负责保护。React框架自首次公布以来,React 的受欢迎水平直线飙升,热度不减。2020 年 10 月,React 17 公布了,但令人诧异的是——“零新性能”。当然,这并不是真的示意没有任何新增加的性能,让宽广程序员使用者兴奋。事实上,这个版本为咱们带来了很多重大性能的降级及16版本的bug修复,并推出了:Concurrent Mode 和Suspense。尽管这两个性能尚未正式公布,这些性能已提供给开发人员进行测试。一旦公布,它们将扭转 React 出现其 UI 的形式,从而达到双倍进步性能和用户体验。 简要阐明, Concurrent Mode 和Suspense 能够使用户无缝解决数据加载,加载状态,用户界面操作更加平滑和无缝切换。 在Concurrent Mode 下,React能够暂停高耗费的,非紧急的组件的渲染,并聚焦在更加紧迫的工作解决,如UI 渲染,始终保持利用为可响应式,防止白屏,卡顿等景象。 本文次要分享深刻理解Concurrent Mode 和Suspense 模式下的数据提取性能。 为什么须要 Concurrent Mode?家喻户晓,JavaScript 框架或库是单线程的工作。因而,当一个代码块运行时,其余的块必须期待执行。无奈并发执行多线程工作。界面渲染也是一样的。一旦 React 开始渲染某些货色,无奈中断直到运行实现。React 开发人员将这种渲染称为“阻塞渲染”。 这种阻塞渲染会创立一个不稳固的用户界面,并且随时可能进行响应。 具体问题如果,咱们须要显示一个很长的可选列表用于过滤产品的应用程序。咱们应用搜寻框用于过滤记录,设计方案是当用户点击搜寻按钮后,用户界面须要从新刷新列出相关联的数据。 如果列表过长,数据过多,UI“卡顿”,即渲染对用户可见。这种卡顿也会大大降低产品性能。开发人员能够应用一些技术,如节流和防抖,这些技术会有肯定帮忙,但不是完满的解决方案。节流限度特定函数被调用的次数。应用节流,咱们能够防止反复调用低廉和耗时的API或函数。这个过程可能进步性能,尤其是在用户界面上出现信息。 防抖会在预约的工夫内疏忽对函数的调用。函数调用仅在通过预约工夫后进行。 下图形容了卡顿景象:在期待非紧急 API 调用实现时,UI 卡顿,从而阻止出现用户界面。解决方案是应用并发模式进行可中断渲染。 无中断渲染通过可中断渲染,React.js 在解决和从新渲染列表时不会阻塞 UI。它通过暂停琐碎的工作、更新 DOM 并确保 UI 不会卡顿,使 React.js 更加细化。React 应用用户输出并行更新或重绘输入框。React 应用用户输出并重绘输入框并行执行。它还更新内存中的列表。React 实现更新后,它会更新 DOM 并在用户的显示器上从新出现列表。实质上,无中断渲染使 React 可能“多任务”。此性能提供了更晦涩的 UI 体验。 ...

July 1, 2021 · 3 min · jiezi

关于react.js:初识React

clsss要用className <div className="color-light">文档的构造当初看来就是在相互援用 小标题scss引入为了看着难受和更快的抉择标签,决定抉择用scss,demo里自带了less,但相对来说scss更相熟些,怎么搞都不胜利 { test: /\.(le|c|sc)ss$/, use: [ MiniCssExtractPlugin.loader, { loader: 'css-loader', }, { loader: 'postcss-loader', options: { ident: 'postcss', plugins: [require('autoprefixer')()], plugins: () => [ //在postcss-loader的插件中退出这个插件 //px2rem({ remUnit: 75 }) 的意思就是1rem = 75px 这个是依据750px设计稿来的,如果是620 的就写 62 px2rem({ remUnit: 75 }) ] }, }, { loader: 'less-loader', }, ], }起初不成只能硬着头皮用less,引入rem2px时发现是增加的地位不对,具体webpack的配置应该就是去掉scss的报错,反正间接和这个less的增加在一起就行没有问题。

June 29, 2021 · 1 min · jiezi

关于react.js:水电费第三方

士大夫撒发是

June 29, 2021 · 1 min · jiezi

关于react.js:Modal和Form结合的-表单对话框-react

版本对应 "antd": "^3.26.14", 如果发现报错 antd__WEBPACK_IMPORTED_MODULE_1__.Form.create(...) is not a function可参考尝试 指定版本 yarn add antd@^3.26.14 -S compponentName.js import React from 'react';import { Form, Input, InputNumber } from 'antd';const { TextArea } = Inputclass EditForm extends React.Component { constructor(props) { super(props); } componentWillMount() { } componentWillReceiveProps(nextProps) { } componentDidMount() { } render() { const { getFieldDecorator } = this.props.form; return <Form labelCol={{ span: 6 }} wrapperCol={{ span: 12 }}> <Form.Item label="账户" > {getFieldDecorator('username', { rules: [ { required: true, message: '账户', }, ], initialValue: this.props.username })(<Input />)} </Form.Item> <Form.Item label="代码"> {getFieldDecorator('code', { rules: [ { required: true, message: '代码', }, ], initialValue: this.props.code })(<Input />)} </Form.Item> <Form.Item label="备注"> {getFieldDecorator('remark', { rules: [ { message: '备注', }, ], initialValue: this.props.remark })( <TextArea row={6} />, )} </Form.Item> </Form> }}export default Form.create()(EditForm);引入与应用 ...

June 29, 2021 · 2 min · jiezi

关于react.js:在-React-框架中集成纯前端报表设计器

创立 React 利用创立 React 利用的最简略的办法是应用 创立 React App, 如应用npx 包运行工具: npm init react-app arjs-react-designer-app或应用yarn命令创立: yarn create react-app arjs-react-designer-app创立 React利用更多可参考文档 官网文档 装置 ActivereportsJS报表设计器相干的文件会蕴含在@grapecity/activereports npm 包中。 装置以后版本,运行以下命令: npm install @grapecity/activereports-react @grapecity/activereports也能够应用 yarn命令: yarn add @grapecity/activereports-react @grapecity/activereports 导入 ActiveReportsJS 款式在 src\App.css 文件夹中导入以设计器须要的款式文件. @import "@grapecity/activereports/styles/ar-js-ui.css";@import "@grapecity/activereports/styles/ar-js-designer.css"; designer-host {width: 100%; height: 100vh;} 将 ActiveReportsJS报表增加到应用程序ActiveReportsJS 应用 JSON格局和rdlx-json扩大用于报表模板文件。在应用程序的public文件夹下,创立名为report.rdlx-json的新文件,并在该文件中插入以下JSON内容。 { "Name": "Report", "Body": { "ReportItems": [ { "Type": "textbox", "Name": "TextBox1", "Value": "Hello, ActiveReportsJS Designer", "Style": { "FontSize": "18pt" }, "Width": "8.5in", "Height": "0.5in" }]}} ...

June 29, 2021 · 2 min · jiezi

关于react.js:React-18-带来了什么

(因为当初 React18 还没正式公布太多的文档,很多概念和内容是我从多个起源拼凑而来,外面蕴含了很多我集体的了解,可能到 React18 正式公布的时候,会有些许谬误,写这个文章仅仅是满足一下好奇心理。所以如果你是在将来的某个工夫内看到这篇文章,你记得去浏览官网的内容,并以官网的内容为主。) 其实 React18@alpha 曾经公布有一段时间了,因为我最近分到一个调研--“UMI 如何反对 react@18 alpha”。(要不然,我应该会持续蹲。) 所以就开始看了看相干的文档和新闻。 比拟好的音讯是,你能够十分平滑的降级到 React18。 比方在 umi 中,抛开测试和兼容之类的代码,仅仅只须要批改一行代码就能够反对。 - import { hydrate, render } from 'react-dom';+ import ReactDOM, { hydrate, render } from 'react-dom';- if (window.g_useSSR) {- hydrate(rootContainer, rootElement, callback);- } else {- render(rootContainer, rootElement, callback);- }+ reactRoot = (ReactDOM as any).createRoot(rootElement, {+ hydrate: window.g_useSSR,+ });+ reactRoot.render(rootContainer);并且改完从业务侧,页面代码中都无需做任何批改我的项目就能够失常的运行。接着你就能够通过选择性的增加 React18 的新个性到你的某些新页面或者优化某些场景。 (看到这里不得不吐槽一下 React Native,发一个小版本都前后不兼容啊!) 开箱即用当你简略的更改了相似下面的代码,你将间接享受到 React18 开箱即用的一些性能。 主动批处理以缩小渲染Suspense 的 SSR 反对(全新的 SSR 架构)主动批处理以缩小渲染批处理使 React 将多个状态更新分组到单个从新渲染中以取得更好的性能。这个个性在当初的 React17 中就曾经有了,然而在不同的上下文中交互的时候,将不反对批处理。当初 React18 中,减少了对网络申请,promise、setTimeout等事件的主动批处理反对。 ...

June 25, 2021 · 2 min · jiezi

关于react.js:react源码解析20总结第一章的面试题解答

react源码解析20.总结&第一章的面试题解答视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 总结至此咱们介绍了react的理念,如果解决cpu和io的瓶颈,要害是实现异步可中断的更新 咱们介绍了react源码架构(ui=fn(state)),从scheduler开始调度(依据过期事件判断优先级),通过render阶段的深度优先遍历造成effectList(两头会执行reconcile|diff),交给commit解决实在节点(两头交叉生命周期和局部hooks),而这些调度的过程都离不开Fiber的撑持,Fiber是工作单元,也是节点优先级、更新UpdateQueue、节点信息的载体,Fiber双缓存则提供了比照前后节点更新的根底。咱们还介绍了jsx是React.createElement的语法糖。Lane模型则提供了更细粒度的优先级比照和计算,这所有都为concurrent mode提供了根底,在这之上变能够实现Suspense和batchedUpdate(16、17版本实现的逻辑不一样),18章context的valueStack和valueCursor在整个架构中运行机制,19章介绍了新版事件零碎,包含事件生产、监听和触发 面试题简答(详见视频源码角度解说)jsx和Fiber有什么关系 答:mount时通过jsx对象(调用createElement的后果)调用createFiberFromElement生成Fiberupdate时通过reconcileChildFibers或reconcileChildrenArray比照新jsx和老的Fiber(current Fiber)生成新的wip Fiber树 react17之前jsx文件为什么要申明import React from 'react',之后为什么不须要了 答:jsx通过编译之后编程React.createElement,不引入React就会报错,react17扭转了编译形式,变成了jsx.createElement function App() { return <h1>Hello World</h1>;}//转换后import {jsx as _jsx} from 'react/jsx-runtime';function App() { return _jsx('h1', { children: 'Hello world' });}Fiber是什么,它为什么能进步性能 答:Fiber是一个js对象,能承载节点信息、优先级、updateQueue,同时它还是一个工作单元。 Fiber双缓存能够在构建好wip Fiber树之后切换成current Fiber,内存中间接一次性切换,进步了性能Fiber的存在使异步可中断的更新成为了可能,作为工作单元,能够在工夫片内执行工作,没工夫了交还执行权给浏览器,下次工夫片继续执行之前暂停之后返回的FiberFiber能够在reconcile的时候进行相应的diff更新,让最初的更新利用在实在节点上hooks 为什么hooks不能写在条件判断中 答:hook会按顺序存储在链表中,如果写在条件判断中,就没法放弃链表的程序 状态/生命周期 setState是同步的还是异步的 答:legacy模式下:命中batchedUpdates时是异步 未命中batchedUpdates时是同步的 concurrent模式下:都是异步的 componentWillMount、componentWillMount、componentWillUpdate为什么标记UNSAFE 答:新的Fiber架构能在scheduler的调度下实现暂停持续,排列优先级,Lane模型能使Fiber节点具备优先级,在高优先级的工作打断低优先级的工作时,低优先级的更新可能会被跳过,所有以上生命周期可能会被执行屡次,和之前版本的行为不统一。 组件 react元素$$typeof属性什么 答:用来示意元素的类型,是一个symbol类型 ...

June 25, 2021 · 2 min · jiezi

关于react.js:React-项目搭建流程一

创立新的 React 单页面利用:1- 在你的机器上装置 Node >= 8.10 和 npm >= 5.6。要创立我的项目,请终端执行:` npx create-react-app my-app` 留神npx 不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。2-终端运行代码cd my-appyarn start3-运行胜利https://upload-images.jianshu...4-文件展现5-干掉不须要的文件后:6-敞开服务器control+c键 7-重新启动我的项目yarn startnpm start8-mock( 模仿 )数据工具json server 获取一个模仿的功能齐全的api接口 不须要敲代码 小于30s即可搞定全局装置json-server命令行工具筹备一个json文件 存储数据 生成接口装置 npm install -g json-server测试 json-server -v启动 json-server data.json --port 4000 -w //设置端口,自动更新数据生成接口 能够申请数据了。更新中。。。

June 24, 2021 · 1 min · jiezi

关于react.js:react源码解析19手写迷你版react

react源码解析19.手写迷你版react视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 迷你react和真正的源码有哪些区别呢在render阶段咱们遍历了整颗Fiber树,在源码中如果节点什么都没扭转会命中优化的逻辑,而后跳过这个节点的遍历commit咱们也遍历了整颗Fiber树,源码中只遍历带有effect的Fiber节点,也就是遍历effectList每次遍历的时候咱们都是新建节点,源码中某些条件会复用节点没有用到优先级第一步:渲染器和入口函数 const React = { createElement, render,};const container = document.getElementById("root");const updateValue = (e) => { rerender(e.target.value);};const rerender = (value) => { const element = ( <div> <input onInput={updateValue} value={value} /> <h2>Hello {value}</h2> </div> ); React.render(element, container);};rerender("World");第二步:创立dom节点函数 /创立elementfunction createElement(type, props, ...children) { return { type, props: { ...props, children: children.map((child) => (typeof child === "object" ? child : createTextElement(child))), }, };}//创立text类型function createTextElement(text) { return { type: "TEXT_ELEMENT", props: { nodeValue: text, children: [], }, };}//创立domfunction createDom(fiber) { const dom = fiber.type === "TEXT_ELEMENT" ? document.createTextNode("") : document.createElement(fiber.type); updateDom(dom, {}, fiber.props); return dom;}第三步:更新节点函数 ...

June 24, 2021 · 5 min · jiezi

关于react.js:写一个简单的JSON-Schema为了应对后台接口细节的口口相传

什么是JSON Schema怎么定义呢,说句实话我是写完了才发现,这不跟传说的JSON Schema差不多么,so,我就说ta是JSON Schema(我了解的,正不正经不晓得)。 正经的定义Json Schema定义了一套词汇和规定,这套词汇和规定用来定义Json元数据,且元数据也是通过Json数据模式表白的。Json元数据定义了Json数据须要满足的标准,标准包含成员、构造、类型、束缚等。我因为啥写始终以来和后盾进行联调这件事都是一件很"困扰"的事件,次要是沟通老本太大,其次要集中在接口文档的沟通上,不是这个参数值不必传,就是那个值必须写的,或者某些参数必须是什么类型的。还都不落实到文档,这么说也不谨严,他有文档,但不“清晰”,还是防止不了沟通,或者有改变他不更新,毕竟制订规矩并严格遵守可没间接口口相传来的“难受”,就是图不便,但这就很危险,大家一旦同步错乱,性能就写错,那节约的人力物力还有空口白牙,没处说理去所引起的心态崩了,这几乎无奈承受,与其在困扰中忍耐,不是想个办法“变一变”,so,我就搞了这个。 那么开始上菜设计思路首先我冀望ta可能在我申请的时候,帮我办两件事: 符不合乎后盾的要求:在申请的时候,对入参(发送给后盾数据)进行相应的校验。符不合乎前台的要求:在申请回数据的时候,对出参(后盾返回的数据)进行相应的校验。而后,在补上一个特点 可配置接下来开整吧☺。 配置办法先贴出配置数据,而后咱们再剖析:import BaseApiShape from './baseApiCheck'let config = { fetchTestDataList: { reqParam: { type: {},//不写默认是对象 p1: { type: "string",//要求是什么类型,传入类型名,否者间接取传入变量的类型 }, p2: { type: {}, }, p13: { type: "string", }, }, resParam: { p1: { type: [], }, p2: { type: {}, } } }, fetchLightDetail: { resParam: { type: [], _item: { lightItems: { type: [], _item: { exclude: { type: "boolean", } }, }, aaaaa: { type: {}, } } } }}export default new BaseApiShape({ config })剖析:下面的两个校验个体十分典型,残缺的把我所有的校验性能都体现进去了: ...

June 23, 2021 · 3 min · jiezi

关于react.js:React错误边界

概述在日常业务开发过程中,咱们对于业务自身的需要实现投入了大量的关注。对于程序的异样解决可能投入精力比拟少。然而对于一个程序的健壮性来说,异样解决是十分十分重要的局部。谬误边界这是React16版本当前,官网提供的一种谬误降级解决计划。 解决了局部问题看下面的文档,这个谬误边界的解决方案只能解决上面几种状况的异样。 渲染期间 render生命周期办法整个组件树的构造函数ok,只有这3中状况下产生异样,才能够捕捉到。 不过,这种谬误是能够冒泡的,也就是说 如果在组件最顶层应用 ErrorBoundary组件,就能捕捉整个组件树的 异样,当然也能够嵌套多处应用。 这没什么须要阐明的,官网文档应用阐明曾经足够清晰。 解决不了的问题谬误边界无奈捕捉的谬误: 事件处理异步代码它本身抛出来的谬误(并非它的子组件)服务端渲染那针对这些场景下的异样,该如何捕捉呢?上面咱们粗略剖析一下可能的解决方案 try/catch咱们本能想到的或者常常应用的可能就是 try/catch语句了。它的确能帮忙咱们捕捉的很多异样,防止程序解体。 当然try/catch 是不是就一劳永逸了呢,当然不。它存在非常明显的两个毛病: 只能捕捉到 同步程序中 产生的异样导出书写trg/catch 真的是有点烦啊unhandledrejection当初promise 曾经烂大巷了,泛滥成灾。到处都是then却没有catch的案例随处可见。这个时候,如果产生了异样,咱们会在控制台看到Uncaught (in promise)等error。这个时候能够监听unhandledrejection谬误事件,专门用来解决promise的未捕捉异样 window.addEventListener("unhandledrejection", event => { console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);});error最大杀手锏,监听error事件,之前做谬误日志收集零碎,次要就是靠这个玩意。 window.addEventListener('error', this.onError, true);有没有集成计划下面粗略的分下了那么多,啊, 看着还是好烦,须要本人到处写,到处手动解决。能不能形象一下啊,有没有轮子能够用啊...连忙去开源社区搜搜啊。到npm.js官网 输出关键词,还真进去不少 react-error-catchreact-error-catcher......总结这个只是简略的思考和记录一下,目前没有精力钻研的十分深刻。不过总体来讲,解决异样的也就是那些根底的货色,根底才是所有的基石。残余的就是如何形象封装出一个比拟好用的库,这就是造轮子的功夫了。不过开源社区资源很宏大,能够借鉴参考应用。

June 23, 2021 · 1 min · jiezi

关于react.js:react源码解析17context

react源码解析17.context视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 查看视频调试demo_7context流程图 cursor/valueStackreact源码中存在一个valueStack和valueCursor用来记录context的历史信息和以后context,另外还有一个didPerformWorkStackCursor用来示意以后的context有没有变动 //ReactFiberNewContext.new.jsconst valueCursor: StackCursor<mixed> = createCursor(null);const didPerformWorkStackCursor: StackCursor<boolean> = createCursor(false);//ReactFiberStack.new.jsconst valueStack: Array<any> = [];function pushProvider(providerFiber, nextValue) { var context = providerFiber.type._context; { push(valueCursor, context._currentValue, providerFiber); context._currentValue = nextValue; }}function popProvider(providerFiber) { var currentValue = valueCursor.current; pop(valueCursor, providerFiber); var context = providerFiber.type._context; { context._currentValue = currentValue; }}在render阶段调用updateContextProvider的时候会执行pushProvider,将新的值push进valueStack中在commit阶段调用completeWork的时候会执行popProvider,将栈顶context pop进去,为什么会有这样一个机制呢,因为咱们的context是跨层级的,在之前讲到render阶段和commit阶段的时候,咱们会以深度优先遍历的形式遍历节点,如果波及跨层级读取状态就有点力不从心了,就须要一层一层往下传递咱们的props,所以咱们能够用一个stack记录咱们的context,在render阶段pushProvider,在commit阶段popProvider,在每个具体的层级能依据valueCursor取以后value ...

June 22, 2021 · 3 min · jiezi

关于react.js:React系列五创建React组件

快来退出咱们吧!"小和山的菜鸟们",为前端开发者提供技术相干资讯以及系列根底文章。为更好的用户体验,请您移至咱们官网小和山的菜鸟们 ( https://xhs-rookies.com/ ) 进行学习,及时获取最新文章。 "Code tailor" ,如果您对咱们文章感兴趣、或是想提一些倡议,微信关注 “小和山的菜鸟们” 公众号,与咱们取的分割,您也能够在微信上观看咱们的文章。每一个倡议或是同意都是对咱们极大的激励! 前言这节咱们将介绍 React 中组件的类别,以及如何创立和应用组件。 本文会向你介绍以下内容: 创立类组件创立函数组件渲染组件合成组件提取组件Props 是只读的组件介绍组件(Components) 让你能够将用户界面分成独立的,可复用的小部件,并能够对每个部件进行独自的设计。 从定义上来说, 组件就像JavaScript的函数。组件能够接管任意输出(称为”props”), 并返回 React 元素,用以形容屏幕显示内容。 Props , 即属性(Property), 在代码中写作 props,故可用 props 指代 properties。react中有两种组件:类组件(class components)、函数组件(function components) 创立类组件类组件的定义有如下要求: 类组件须要继承自 React.Component类组件必须实现render函数在ES6之前,能够通过create-react-class 模块来定义类组件,然而目前官网倡议咱们应用ES6的class类定义。 应用class定义一个组件: class App extends Component { constructor() { super() this.state = {} } render() { return <h2>Hello App</h2> }}咱们来详细分析一下类组件有哪几个局部 constructor:这是类组件的构造函数,是可选的,咱们通常在constructor中初始化一些数据;this.state:咱们在constructor中给类组件退出state属性,你能够了解为组件中有一个state对象,其中蕴含着各种属性,用于保护组件外部的数据。同时你能够通过this.state.<属性名>拜访该属性;render(): 该办法是 class 组件中惟一必须实现的办法,类组件通过render()返回组件的显示内容;对于 state咱们能够通过this.state给类组件增加数据对象,咱们能够通过this.state.<属性名>去拜访咱们setState中的属性。 constructor(props) { super(props); this.state = { name:"xhs-rookies" } }render(){ return <h2>{this.state.name}</h2> }然而咱们想要批改上述例子中的name属性的时候,则必须通过react给咱们规定好的setState()办法,去给state增加或者批改其中的数值。 ...

June 21, 2021 · 2 min · jiezi

关于react.js:Vite-React-组件开发实践

简介: 毫不夸大的说,Vite 给前端带来的相对是一次革命性的变动。或者也能够说是 Vite 背地整合的 esbuild 、 Browser es modules、HMR、Pre-Bundling 等这些社区中对于 JS 编译倒退的先进工具和思路,在 Vite 这样的整合推动下,给前端开发带来了革命性变动。 作者 | 风水起源 | 阿里技术公众号 去年发表的《一个好的组件应该是什么样的?》 一文介绍了借助 TypeScript AST 语法树解析,对 React 组件 Props 类型定义及正文提取,主动生成组件对应 截图、用法、参数阐明、README、Demo 等。在社区中获得了比拟好的反应,同时利用在团队中也获得了较为不错的后果,当初外部组件零碎中曾经累计应用该计划积淀 1000+ 的 React 组件。 之前咱们是借助了 webpack + TypeScript 做了一套用于开发 React 组件的脚手架套件,当开发者要组件开发时,即可间接应用脚手架初始化对应我的项目构造进行开发。 尽管主门路上的确解决了组件开发中所遇到的组件无图无假相、组件参数文档缺失、组件用法文档缺失、组件 Demo 缺失、组件无奈索引、组件产物不标准等外部组件治理和积淀上的问题,但 Webpack 的计划始终还是会让组件开发多一层编译,当一个组件库积淀超过 300+ 时,引入依赖一直增长,还是会带来组件编译上的负荷导致开发者开发体验降落。 一 Vite 带来的曙光Vite 给前端带来的相对是一次革命性的变动,这么说毫不夸大。 或者应该说是 Vite 背地整合的 esbuild 、 Browser es modules、HMR、Pre-Bundling 等这些社区中对于 JS 编译倒退的先进工具和思路,在 Vite 这样的整合推动下,给前端开发带来了革命性变动。 我很早就说过,任何一个框架或者库的呈现最有价值的肯定不是它的代码自身,而是这些代码背地所带来的新思路、新启发。所以我在写文章的时候,也很重视能把我思考最初执行的整个过程讲清楚。 Vite 为什么快,次要是 esbuild 进行 pre-bundles dependencies + 浏览器 native ESM 动静编译,这里我不做过多赘述,具体参考:Vite: The Problems ...

June 21, 2021 · 3 min · jiezi

关于react.js:react源码解析16concurrent模式

react源码解析16.concurrent模式视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo concurrent modereact17反对concurrent mode,这种模式的基本目标是为了让利用放弃cpu和io的疾速响应,它是一组新性能,包含Fiber、Scheduler、Lane,能够依据用户硬件性能和网络情况调整利用的响应速度,外围就是为了实现异步可中断的更新。concurrent mode也是将来react次要迭代的方向。 cup:让耗时的reconcile的过程能让出js的执行权给更高优先级的工作,例如用户的输出,io:依附SuspenseFiberFiber咱们之前介绍过,这里咱们来看下在concurrent mode下Fiber的意义,react15之前的reconcile是同步执行的,当组件数量很多,reconcile时的计算量很大时,就会呈现页面的卡顿,为了解决这个问题就须要一套异步可中断的更新来让耗时的计算让出js的执行权给高优先级的工作,在浏览器有闲暇的时候再执行这些计算。所以咱们须要一种数据结构来形容实在dom和更新的信息,在适当的时候能够在内存中中断reconcile的过程,这种数据结构就是Fiber。 SchedulerScheduler独立于react自身,相当于一个独自的package,Scheduler的意义在于,当cup的计算量很大时,咱们依据设施的fps算出一帧的工夫,在这个工夫内执行cup的操作,当工作执行的工夫快超过一帧的工夫时,会暂停工作的执行,让浏览器有工夫进行重排和重绘。在适当的时候持续工作。 在js中咱们晓得generator也能够暂停和持续工作,然而咱们还须要用优先级来排列工作,这个是generator无奈实现的。在Scheduler中应用MessageChannel实现了工夫切片,而后用小顶堆排列工作优先级的高下,达到了异步可中断的更新。 Scheduler能够用过期工夫来代表优先级的高下。 优先级越高,过期工夫越短,离以后工夫越近,也就是说过一会就要执行它了。 优先级越低,过期工夫越长,离以后工夫越长,也就是过很久了能力轮到它执行。 laneLane用二进制位示意工作的优先级,不便优先级的计算,不同优先级占用不同地位的‘赛道’,而且存在批的概念,优先级越低,‘赛道’越多。高优先级打断低优先级,新建的工作须要赋予什么优先级等问题都是Lane所要解决的问题。 batchedUpdates简略来说,在一个上下文中同时触发屡次更新,这些更新会合并成一次更新,例如 onClick() { this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 });} 在之前的react版本中如果脱离以后的上下文就不会被合并,例如把屡次更新放在setTimeout中,起因是处于同一个context的屡次setState的executionContext都会蕴含BatchedContext,蕴含BatchedContext的setState会合并,当executionContext等于NoContext,就会同步执行SyncCallbackQueue中的工作,所以setTimeout中的屡次setState不会合并,而且会同步执行。 onClick() { setTimeout(() => { this.setState({ count: this.state.count + 1 }); this.setState({ count: this.state.count + 1 }); });}export function batchedUpdates<A, R>(fn: A => R, a: A): R { const prevExecutionContext = executionContext; executionContext |= BatchedContext; try { return fn(a); } finally { executionContext = prevExecutionContext; if (executionContext === NoContext) { resetRenderTimer(); //executionContext为NoContext就同步执行SyncCallbackQueue中的工作 flushSyncCallbackQueue(); } }} 在Concurrent mode下,下面的例子也会合并为一次更新,根本原因在如下一段简化的源码,如果屡次setState,会比拟这几次setState回调的优先级,如果优先级统一,则先return掉,不会进行前面的render阶段 ...

June 21, 2021 · 1 min · jiezi

关于react.js:数栈技术分享利用-Atomic-构建-React-项目工作流so-easy

数栈是云原生—站式数据中台PaaS,咱们在github和gitee上有一个乏味的开源我的项目:FlinkX,FlinkX是一个基于Flink的批流对立的数据同步工具,既能够采集动态的数据,也能够采集实时变动的数据,是全域、异构、批流一体的数据同步引擎。大家喜爱的话请给咱们点个star!star!star! github开源我的项目:https://github.com/DTStack/fl... gitee开源我的项目:https://gitee.com/dtstack_dev... 用过 React 的敌人都晓得,React 我的项目文件夹的划分是有很多种的,在 React 官网对于文件构造这个局部给出了一些社区比拟常见的构建形式的示例。例如有通过features或者routes进行分组的,也有通过模块类型(type) 划分的。在文档提到了一种针对components 进行细化组织的办法 —— Atomic Design。如果还没理解过这个设计办法的敌人,无妨来看一看。一、什么是Atomic Atomic 是一套领导设计前端组件(Components)架构的办法。在咱们的日常工作中,如何更好的划分和治理前端组件经常会是咱们碰到的问题。Atomic 通过一系列设计思维和准则,能够很好领导咱们的我的项目架构。用 Atomic 作者本人的话说,这套设计办法的灵感是来自于本人已经学习过的化学课,以及对天然常识自身的思考。作者通过原子(Atoms)、分子(Molecules)、 有机体(Organisms)、模板(Templates), 页面(Pages) 这5种根本类型组件,通过灵便的组合,从而来满足咱们日常的页面开发需要。 1、原子(Atoms) 正如化学常识中所表述的,原子(Atoms)是元素能放弃其化学性质的最小单位,所以正好利用原子的概念,能够用来组件零碎中的最小单位的组件,或者说形象到最小粒度的组件,即咱们在 HTML 中常见的一些根本元素,例如:按钮(buttons),表单标签(labels),输出控件(input)等等。既然是最小单位,Atom 类型的组件显然是无奈再进行任何拆分了,如果能持续拆分,那么该组件应该被划分为分子组件(Molecules)。 2、分子(Molecules) 咱们都晓得,在化学概念中,分子是有若干原子组成。通过组合各种原子组件,咱们能够轻易的能够组合出某种性能的分子组件。例如通过组合 input 控件和 button 组件,咱们能够失去一个搜寻(Search)分子组件,通过组合 button 和 a 标签,能够能够组合分页(Pagination)组件。 3、有机体(Organisms) 仅靠分子组件和分子组件的形象,依然是不能满足咱们理论工作中对组件复用的需要,例如咱们咱们大部分我的项目中都有导航栏(Navigation Bar)、页头(Header)、页脚(Footer)、边栏(Sidebar)、列表(List) 等等组件,显然能够依据须要能够形象成独立组件,以便起初的我的项目能够间接应用。能够看到的是,在有原子和分子组件的状况下,咱们通过灵便组合这些原子、分子组件的形式,便可轻易达到咱们的需要。而通过这类形式组合的组件类型咱们便称之为有机体组件(Organisms)。 4、模板(Templates) 到这里,模板层就很好了解了。很显然,模板层是原子、分子、有机组件的结合体。例如蕴含头部(Header、Content、Footer)常见局部的首页模板、又或者各种左右高低布局模板组件等等。 5、页面(Pages) 页面这一层可能是复用率最低的一层了,因为业务需要大部分时候各不相同的,当然也不排除有复用页面的状况。页面组件天然就是个蕴含了其余四种组件类型的综合体了。有了前几层组件的形象,能够轻松的应答各种业务页面,并且一直地能够丰盛新组件到各类型本人中去,以便前面的我的项目中继续应用。 综合看下来,通过这5种组件的划分,就能够很好的满足咱们理论我的项目中对页面组件进行划分和治理了。 二、Atomic实际 依据 Atomic 的思路, 以 src 目录为根底,在 React 我的项目中,我能够失去了相似如下的开发目录: 当然,像我通常喜爱把 pages 的层级进步,也就是把他与 components 同层,也就是: 这里有个仓库 Demo 能够参考: ...

June 18, 2021 · 1 min · jiezi

关于react.js:COMP-2034-Software-Development

Software DevelopmentPython Programming Assignment 2UniSA STEMThe University of South AustraliaMay 2021 2 -ContentsIntroductionGraduate QualitiesSpecifications and RequirementsSubmission RequirementsExtensions and Late SubmissionsAcademic MisconductSample OutputMarking Criteria3 -IntroductionThis document describes the second programming assignment for COMP 2034 SoftwareDevelopment course.The assignment is intended to provide you with the opportunity to put into practice whatyou have learnt in the course by applying your knowledge and skills in Object-OrientedProgramming with Python programming language. The task is to develop a program withmultiple modules which allows users to play the game of Rock-Paper-Scissors or the game ofCode Break against the computer and maintains information on players. Player informationwill be stored in a text file that will be read in when the program commences. Once theapplication has read the initial player data, it should allow the user to interactively queryand manipulate the player information as well as play games against the computer.This assignment is an individual task that will require an individual submission. Eachstudent is required to submit your work via LearnOnline system by the deadline specifiedin the Submission Requirements section of this document.This document is a specification of the required end product that will be generated byimplementing the assignment. Like many specifications, it is written in English and hencewill contain some imperfectly specified parts. Please make sure you seek clarification if youare not clear on any aspect of this assignment.4 -Graduate QualitiesBy undertaking this assessment, you will progress in developing the qualities of a Universityof South Australia graduate. The Graduate qualities being assessed by this assignment are:• The ability to demonstrate and apply a body of knowledge (GQ1) gained from thelectures, practicals, and readings. This is demonstrated in your ability to applyprogramming theory to a practical situation.• The ability to effectively problem solve (GQ3) using Python and Object-OrientedProgramming concepts to complete the programming problem. Effective problemsolving is demonstrated by the ability to understand what is required, utilise therelevant information from lectures, the text book and practical work, write Pythoncode, and evaluate the effectiveness of the code by testing it.• The use of communication skills (GQ6) by producing source code that has beenproperly formatted; and by writing adequate, concise and clear comments.Communicating with others through demonstrating and explaining the programcode to the instructor.5 -Specifications and RequirementsYour solution MUST adhere to the specifications and requirements described in thisdocument.It is recommended that you develop this assignment in stages and make back-ups of yourcode regularly not only for development purpose, but also as an evidence of original work.Your program must be developed using multiple Python modules, with the number andnames of all the files strictly adhering to the specifications below.Your program must be developed with six Python files, three of them provided, and three ofthem newly written by yourself. These files must be:• assignment2.py - This file contains the main part of your program to import theother modules and run. It allows the user to interactively query and manipulate theplayer information and play games. (PROVIDED)• player.py - This file contains Player class definition to store a single playerinformation.• leaderboard.py - This file contains LeaderBoard class definition to manageplayers on a leader board.• game.py - This file contains Game class definition which is the base class of othergame classes. (PROVIDED)• rpsgame.py - This file contains RockPaperScissors class definition whichimplements the Rock-Paper-Scissors game. (PROVIDED)• codebreakgame.py - This file contains CodeBreak class definition whichimplements the Code Break game.Three files (assignment2.py, game.py, rpsgame.py) will be provided on the coursewebsite along with this document and they must be used without any modification. Tosolve this assignment, you must create and write three additional files player.py,leaderboard.py, and codebreakgame.py.Program BehaviourWhen your run the program assignment2.py, it will create an instance object of theLeaderBoard class you define and call the load() method which should load in playerinformation from a file called players.txt (provided on the course website). If theprogram has loaded the data successfully, the following message will be displayed:Players info successfully loaded.Or if the program fails to load the players info, the following message will be displayed:ERROR: Cannot load players info.Your program will enter the command mode after the player information has been loadedfrom the file. In the command mode, the program reads user input for a command with thefollowing prompt shown on the screen:6 -Please enter a command [list, add, remove, play, winner,quit]:The program will allow the user to enter commands and process these commands until the‘quit’ command is entered.The following commands must be supported:Command Descriptionlist Displays the leader board (a list of all players and theirdetails) by calling the display() method of theLeaderBoard object.add Prompts to input a name for a new player to add, and callsthe addPlayer() method of the LeaderBoard objectto add the player with the provided name. Depending onthe return value from the addPlayer() method, thefollowing messages are displayed on the screen with theplayer’s NAME :returned True: "Successfully added player NAME. "returned False: "Player NAME already exists. "remove Prompts to input the player’s name to remove then callsthe removePlayer() method of the LeaderBoardobject to remove the player with the given name.Depending on the return value, the following messagesare displayed on the screen with the player’s NAME :returned True: "Successfully removed player NAME. "returned False: "No such player found."play Asks to input the player’s name who will play the game,and checks the player’s points by calling thegetPlayerPoints() method of the LeaderBoardobject. If the player is not found (i.e. the return value isnegative), an error message “No such player found.” isdisplayed to the screen, otherwise asks for the amount ofpoints to bid, then asks to choose which game to play. Thechosen game will be played by creating an instance ofeither RockPaperScissors or CodeBreak class,then calling its play() method which will return theresult of the game (1: win, 0: tie, -1: lose). After playingthe game, the returned results and the points bid will bepassed on to calling the recordGamePlay() method ofthe LeaderBoard object to update the playerinformation.winner Prints the details of the winning player who has thehighest number of points by calling the getWinner()method of the LeaderBoard object.7 -quit Causes the program to quit, displaying a message “Thankyou for playing!”. Upon quitting, the program will call thesave() method of the LeaderBoard object which willsave the player information to a file named output.txtwhich is in the same format as the input players.txtfile. Upon successfully saving the information the programwill show a message, “Players info successfully saved.” If itfails saving the information, the program will show amessage, “ERROR: Cannot save players info.”debug This is a hidden command (not shown in the prompt) thatwill turn the debug mode on or off. If the debug mode ison, the debugMode property of the game object will beset to True which will let the answer be printed.After performing each command, the program returns to command mode, prompting theuser to input next command.Class SpecificationsBelow are detailed specifications of the three classes you must define in three files:player.py, leaderboard.py, and codebreakgame.py.• Player classThe Player class stores the information for each player. This class must be defined in theplayer.py file, and must have the following public data attributes:Data AttributesA string, name of the player which may include white spaces.An integer, number of games playedAn integer, number of games wonAn integer, number of games lostAn integer, number of games tiedAn integer, current pointsThe Player class must have an initialiser method that takes the name of the player as aparameter, and initialises the name data attribute, as well as sets the rest of the attributesto 0, except the current points which must be initialised to 100.The Player class must also have a string conversion method that returns a stringdescribing the player object including the name, the number of games played, winning rate,and the current points remaining. For example, for a player named "John Doe" who haswon 4 games out of 7 games and has 75 remaining points, it must return a string in thefollowing format:"John Doe has 75 points and a winning rate of 57.1%."Note the winning rate should show 1 digit under the decimal point.8 -If the player did not play any games, the string must be in the following format:"John Doe has 100 points, and never played a game."• LeaderBoard classThe LeaderBoard class manages a list of players (i.e., instance objects of the Playerclass). The LeaderBoard class must be defined in the leaderboard.py file, and musthave only one private (i.e. hidden) data attribute which is the list of players.The LeaderBoard class must define eight public methods, load(), save(),display(), addPlayer(), removePlayer(), getPlayerPoints(),getWinner(), and recordGamePlay(), as well as two private methods,__findPlayer() and __sortPlayers(). Below are detailed specifications of eachmethod:load()This method loads in the player information from a file named players.txt (provided onthe course website together with this document). It reads in the file and creates a list ofinstances of the Player class you defined, and updates the list of players data attributewith the loaded information. In the players.txt file, each player is described in twolines of text. The name of the player (which may include white spaces) is stored in the firstline. The very next line contains the number of games played, games won, games lost,games tied, and the current remaining points, all stored in one line and separated by thespace character. Below is a sample content of the players.txt file with three players:John Doe4 0 1 70Lisa Smith13 2 1 105Andrew Whittaker0 7 0 55You must use the input file players.txt provided on the course website. You are notsupposed to create it yourself or edit the provided input file. You may assume that all datain this file is in the correct format. Note there could be empty lines at the end of the filewhich should be ignored.After loading the data, the load() method must call the __sortPlayers() method tokeep the player list in the order of their points. It should not print any message onto thescreen, but must return True if the data has been successfully loaded, or False if there isany error.save()This method saves the player information to the output.txt file which should have thesame format as the input players.txt file. It should not print any message onto thescreen, but must return True if the data has been successfully saved, or False if there isany error.9 -display()This method shows the leader board onto the screen in the format as described below:• The player name field is displayed under the “Player Name” heading, and should be 30characters wide, left justified.• The number of games played is displayed under the “P” heading, and should be 2characters wide, right justified.• The number of games won is displayed under the “W” heading, and should be 2characters wide, right justified.• The number of games lost is displayed under the “L” heading, and should be 2characters wide, right justified.• The number of games tied is displayed under the “T” heading, and should be 2characters wide, right justified.• The winning rate is displayed under the “W-Rate” heading, and should be 6 characterswide, right justified, showing 1 digit under the decimal point with a percent sign (%) atthe end (Hint: 100.0% has 6 characters). Note that the winning rate is not part of theinformation stored in the Player structure, but should be calculated based on numberof games played and number of games won. If the number of games played is zero,the winning rate is treated as zero percent.• The points is displayed under the “Points” heading, and should be 6 characters wide,right justified.• Each of the field should be separated by a single empty space character. ...

June 17, 2021 · 23 min · jiezi

关于react.js:响应式编程在-SAP-标准产品-UI-开发中的一个实践

这是 Jerry 2021 年的第 42 篇文章,也是汪子熙公众号总共第 319 篇原创文章。 Jerry 在从事 SAP Commerce Cloud 前台 Angular 开发时,脑子里始终记挂着本人已经习得的 SAP UI5 开发技术。我刻意要求本人将 SAP UI5 和 Angular 各方面做比照,只心愿本人能在这两个前端开发框架上,都有肯定的技术积攒。 最近遇到 SAP 电商云前台开发的一个问题,波及到 CombineLatest 这个操作符的用法,所以有了这篇文章。 在 SAP 电商云源代码里依据关键字 CombineLatest 进行搜寻,失去 170 条搜寻后果。这阐明其在 SAP 电商云前台开发里应用是相当宽泛的。 那么这个 CombineLatest 操作符,是利用在什么样的业务场景下呢?答案是响应式编程 (Reactive Programming) 畛域。 Jerry 之前的文章,Jerry在2020 SAP寰球技术大会的分享:SAP Spartacus技术介绍的文字版,已经提到过 SAP Commerce Cloud 新一代基于开源我的项目 Spartacus 我的项目的前端界面,反对响应式 (Responsive) 布局和自适应 (Adaptive) 布局的个性。再加上本文的响应式 (Reactive) 编程,这三个形容词,我刚开始接触的时候感觉很容易弄混同。 Responsive 设计:响应式设计通过各种前端技术,为页面元素赋予了依据屏幕分辨率的变动而主动调整显示行为,以达到最佳显示成果的能力。Adaptive 设计:为不同类别的设施别离实现不同的页面,检测到设施分辨率后调用对应的网页。Reactive 编程:响应式编程是一种编程格调的名称,是咱们解决异步和并发畛域编程问题的一把利器。响应式编程通常蕴含事件驱动,推送机制,观察者发布者模式等特色, 实质上工作于异步数据流上。响应式编程构建出的事件反馈零碎具备高度的可扩展性,本文后续会通过例子给大家展现。为了升高例子的复杂度,便于大家了解,Jerry 把之前在 SAP Commerce Cloud 中遇到的问题,形象成一个简略的模型,别离用 SAP UI5 传统的事件处理形式,和应用 Angular RxJs 响应式编程库两种办法别离实现,大家从中能够感触差别。 ...

June 16, 2021 · 2 min · jiezi

关于react.js:React性能优化之memouseMemouseCallback的使用与区别

因为react的state状态发生变化,子组件也会从新执行render,所以为了防止不必要的性能节约,只能咱们本人去做优化了,在类组件中,咱们会应用PureComponent,每次会对props进行一次浅比拟,当然咱们也能够在shouldComponentUpdate,去做更深层次的比对 在函数式组件中,react提供了React.memo,和hooks useMemo(),也能够封装一个HOC,在外部实现PureComponent + shouldComponentUpdate(下篇会写源码) 一、React.memo() import React, {memo} from 'react'; const isEqual =(prev,next)=> { console.log(prev,next) if(prev.step !== next.step) { return false; } return true; } const Demo1 = (props)=>{ console.log('demo1----render'); const {step} = props; return ( <div> <div> <div>demo1</div> <div>step: {step}</div> </div> </div> ) }通过对2次的props进行比拟,如果第二个参数不传递,则默认进行浅比拟 二、useMemo()有时候咱们只须要对组件中的某一块进行优化,当count发生变化时useMemo会从新执行 import React, {useMemo} from 'react'; const Demo2 = (props)=>{ const {count} = props; const countCom = useMemo(()=> <div>count: {count}</div>, [count]); return( <div> <div className="content"> <div>demo2</div> {countCom} </div> </div> ) }三、useCallback() ...

June 15, 2021 · 1 min · jiezi

关于react.js:盘点那些-React-Hooks-里常见的问题

原文:https://juejin.cn/post/697243... 作者:Tonychen Infinite Chain Of Update理论应用中有时候会碰到 Infinite Chain Of Update 这个报错,其实就是你的一段代码引发了「死循环更新」。上面咱们来看几个例子 依赖数组问题比如说在应用 useEffect 时没有传入依赖数组 // count 会有限 + 1function App() { const [count, setCount] = useState(0) useEffect(() => { setCount(count + 1) })}为什么说 count 会有限更新?这里的逻辑是这样的 组件更新执行 useEffect更新 count 并触发组件更新执行 useEffect…… 解决办法很简略,只有给 useEffect 传一个空数组作为第三个参数,下次更新时 useEffect 便不会执行。 // 失常渲染function App() { const [count, setCount] = useState(0) useEffect(() => { setCount(count + 1) }, [])}监听了被更新的值这个算是老手 hooks 玩家常常会遇到、新手也有些头疼的问题。 案例1useEeffect 中更新的 state 间接影响了被监听的变量,举个例子 function App() { const [obj, setObj] = useState({a: 0}) const {a} = obj useEffect(() => { setObj({ ...obj, a: 1 }) }, [a, obj])}下面这段代码在理论运行的时候就会导致死循环,为什么呢?因为在 setObj 的时候扭转的是 obj 这个值,而 useEffect 监听了这个值,从而 导致了死循环…… ...

June 11, 2021 · 2 min · jiezi

关于react.js:react源码解析11生命周期调用顺序

react源码解析11.生命周期调用程序视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 各阶段生命周期执行状况函数组件hooks的周期会在hooks章节解说,这一章的使命周期次要针对类组件,各阶段生命周期执行状况看下图: render阶段: mount时:组件首先会经验constructor、getDerivedStateFromProps、componnetWillMount、renderupdate时:组件首先会经验componentWillReceiveProps、getDerivedStateFromProps、shouldComponentUpdate、rendererror时:会调用getDerivedStateFromErrorcommit阶段 mount时:组件会经验componnetDidMountupdate时:组件会调用getSnapshotBeforeUpdate、componnetDidUpdateunMount时:调用componnetWillUnmounterror时:调用componnetDidCatch其中红色的局部不倡议应用,须要留神的是commit阶段生命周期在mutation各个子阶段的执行程序,能够温习上一章 接下来依据一个例子来解说在mount时和update时更新的具体程序: mount时:首先会依照深度优先的形式,顺次构建wip Fiber节点而后切换成current Fiber,在render阶段会顺次执行各个节点的constructor、getDerivedStateFromProps/componnetWillMount、render,在commit阶段,也就是深度优先遍历向上冒泡的时候顺次执行节点的componnetDidMountupdate时:同样会深度优先构建wip Fiber树,在构建的过程中会diff子节点,在render阶段,如果返现有节点的变动,例如上图的c2,那就标记这个节点Update Flag,而后执行getDerivedStateFromProps和render,在commit阶段会顺次执行节点的getSnapshotBeforeUpdate、componnetDidUpdate

June 11, 2021 · 1 min · jiezi

关于react.js:react使用windowonscroll不起作用的问题

做滚动加载的过程中发现,window.onsrcoll在react函数式组件中,不起作用,写在生命周期里也还是不行,几经周折,终于搞定 1. useEffect(()=> { // 1.绑定滚动元素并增加scroll事件,组件销毁时移除 const scrollDom = document.getElementById('wrapper') scrollDom.addEventListener('scroll', handleScroll) return () => scrollDom.removeEventListener('scroll', handleScroll); }, [handleScroll]) 2. const handleScroll = useCallback(event => { const height = scrollEvent(event) if (hasMore && height <= 60) { const t =pageIndex+1; setPageIndex(t); setHasMore(false); // 须要扭转状态不然会霎时加载完所有 } }, [hasMore,pageIndex]) 3. 计算间隔底部的间隔 const scrollEvent = event => { if (!event.srcElement.scrollTop) { // 解决向上使劲滚动的时候scrollTop为undefined return undefined } // 滚动的高度 const scrollTop = (event.srcElement ? event.srcElement.scrollTop : false) || window.pageYOffset || (event.srcElement ? event.srcElement.body.scrollTop : 0) // 视窗高度 const clientHeight = (event.srcElement && event.srcElement.clientHeight) || document.body.clientHeight // 页面高度 const scrollHeight = (event.srcElement && event.srcElement.scrollHeight) || document.body.scrollHeight // 间隔页面底部的高度 const height = scrollHeight - scrollTop - clientHeight return height } 4.监听页数变动申请数据 useEffect(() => { getData(); }, [pageIndex]); 5. axios().then(res=> { if(!res||res.length === 0){ setHasMore(false); return; } const newList = dataArr.concat(res); setDataArr(newList); setHasMore(true); }); 如果有问题,感激斧正,如果帮忙到您1分也是爱! ...

June 9, 2021 · 1 min · jiezi

关于react.js:MySQL数据库中常见的日志文件有什么用处

前端人员肯定要把握MySQL数据库,而日志文件记录了影响MySQL数据库的各种类型流动,因而也成为其必须要把握的常识。明天千锋ava培训小编就给大家介绍MySQL数据库中常见的日志文件。 MySQL数据库中常见的日志文件有谬误日志、二进制日志、慢查问日志和查问日志。 谬误日志 谬误日志文件对MySQL的启动、运行、敞开过程进行了记录。比方: mysql> show variables like 'log_error'; | Variable_name | Value | | log_error | /var/log/mysqld.log | 1 row in set (0.03 sec) 能够看到谬误日志的门路和文件名,默认状况下谬误文件的文件名为服务器的主机名,即:hostname.err。当呈现MySQL数据库不能失常启动时,第一个必须查找的文件就是谬误日志文件,该文件记录了出错信息,可能帮忙咱们找到问题。 二进制日志 二进制日志记录了对数据库执行更改的所有操作,然而不包含select和show这类操作,因为这类操作对数据自身并没有批改,如果你还想记录select和show操作,那只能应用查问日志了,而不是二进制日志。 此外,二进制还包含了执行数据库更改操作的工夫和执行工夫等信息。二进制日志次要作用有:复原(recovery)、复制(replication)、审计(audit),你能够通过配置参数 log-bin[=name] 能够启动二进制日志。如果不指定name,则默认二进制日志文件名为主机名,后缀名为二进制日志的序列号。 慢查问日志 慢查问日志用来记录响应工夫超过阈值的SQL语句,所以咱们能够设置一个阈值,将运行工夫超过该值的所有SQL语句都记录到慢查问日志文件中。该阈值能够通过参数long_query_time来设置,默认为10秒。慢查问日志剖析工具包含mysqldumpslow命令、pt-query-digest工具。 查问日志 查看日志记录了所有对MySQL游戏数据库申请的信息,不管这些申请是否失去了正确的执行。默认为主机名www.sangpi.com.log。默认状况下不启动查问日志,必须要先开启。参考代码: mysql> set global general_log='ON'; Query OK, 0 rows affected (0.05 sec) mysql> show variables like "general_log%"; | Variable_name | Value | | general_log | ON | | general_log_file | /var/lib/mysql/iz2zeaf3cg1099kiidi06mz.log | 2 rows in set (0.11 sec)

June 9, 2021 · 1 min · jiezi

关于react.js:解读官方博客React18真的来了

9日凌晨1点,React官网博客放出v18最新进展。 官网带来的三条音讯在React18工作打算这篇博文中,官网带来了三条音讯。 v18的工作曾经在进行中,并且会是下一个次要版本创立了v18工作组,让社区的专家、开发者、库作者先试用v18,为社区的泛滥库前置兼容CM(Concurrent Mode)、教育社区做筹备 工作组地址公布了v18 Alpha版本,以便库作者能够尝试并提供反馈应用v18 Alpha接下来咱们解读下音讯背地的信息。 垫脚石垫的是什么咱们晓得,v17是垫脚石版本,用以稳固CM。 CM之所以难以稳固,一句话概括起因: CM为React带来利用层面的Breaking Change,而且是前所未有的这里带来的工作量包含两局部: 为反对v18的新个性付出的开发成本帮社区渐进降级到v18付出的开发、沟通老本新个性付出的开发成本v18的次要个性流式SSR前置依赖不同优先级的Suspense。 不同优先级的Suspense前置依赖更灵便的CM。 这里的灵便指优先级之间不仅能够独自比拟,还能以批的概念相互比拟。 所以Andrew在v16.13.1时须要先实现lanes优先级调度算法的开发。 同时,底层反对更灵便的CM后,也为下层带来了诸如: startTransition、useDeferredValue这样的API,能够让开发者显式的指定UI渲染的优先级。比方:能够利用useDeferredValue,依据用户设施性能(qps),实现主动的debounce性能。 新API,比方OffScreen(能够了解为React版的keep-alive)主动batchUpdate,不仅局限在事件回调函数中为社区渐进降级付出的老本官网还在最新进展中走漏,降级到v18将不会、或很少的扭转现有代码。 起因是:CM是可选的(也就是说工夫切片是默认敞开的)。 方才聊到,CM前置依赖优先级调度,而优先级调度是在工夫切片这一架构上实现的。 所以,当工夫切片被默认敞开后,现有代码简直不须要改变就能够平滑降级到v18。 能够看到,工夫切片个性被标记为Umbrella,代表这一个性会影响很多API、架构、库在v17公布时,React外部重构了事件机制。 React事件不会冒泡到对立的根节点,而是每个利用(即调用ReactDOM.render的节点)的根节点。 这就能让整个利用中的一部分放弃现有的legacy模式,新的局部启用CM,因为这两个子利用是互相独立的。 因为CM带来的Breaking Change使一大票库都不兼容(比方mobx),所以React还专门开发了新API —— create-subscription用于订阅内部依赖。 这也是为什么v18 Alpha会优先让库作者应用 —— 库现有的实现在开启CM全功能时,有可能不兼容。 工夫点以后v18 Alpha曾经可用。公开的beta版会在几个月后公布。 在beta版收回后几周后,会公布RC版本。 最初,在RC版本后至多几周后,稳固版本会公布。 所以整体的预计是:v18稳定版年底会到来。 届时,React团队的工作重心将放在Server Components上。 React该如何进阶,最高效的React源码级进阶之路

June 9, 2021 · 1 min · jiezi

关于react.js:react源码解析9diff算法

react源码解析9.diff算法视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 在render阶段更新Fiber节点时,咱们会调用reconcileChildFibers比照current Fiber和jsx对象构建workInProgress Fiber,这里current Fiber是指以后dom对应的fiber树,jsx是class组件render办法或者函数组件的返回值。 在reconcileChildFibers中会依据newChild的类型来进入单节点的diff或者多节点diff //ReactChildFiber.old.jsfunction reconcileChildFibers( returnFiber: Fiber, currentFirstChild: Fiber | null, newChild: any,): Fiber | null { const isObject = typeof newChild === 'object' && newChild !== null; if (isObject) { switch (newChild.$$typeof) { case REACT_ELEMENT_TYPE: //繁多节点diff return placeSingleChild( reconcileSingleElement( returnFiber, currentFirstChild, newChild, lanes, ), ); } } //... if (isArray(newChild)) { //多节点diff return reconcileChildrenArray( returnFiber, currentFirstChild, newChild, lanes, ); } // 删除节点 return deleteRemainingChildren(returnFiber, currentFirstChild);}diff过程的次要流程如下图: ...

June 9, 2021 · 4 min · jiezi

关于react.js:React进阶探案揭秘六种React‘灵异现象

前言明天咱们来一期不同寻常的React进阶文章,本文咱们通过一些不同寻常的景象,以探案的流程剖析起因,找到后果,从而意识React,走进React的世界,揭开React的面纱,我坚信,更深的了解,方可更好的应用。 我抵赖起这个名字可能有点题目党了,灵感来源于小时候央视有一个叫做《走进迷信》的栏目,天天介绍各种超自然的灵异景象,搞的神乎其神,最初揭秘的时候原来是各种小儿科的问题,当初想想都感觉搞笑。然而我明天介绍的这些React '灵异'景象实质可不是小儿科,每一个景象后都走漏出 React 运行机制和设计原理。(咱们讲的react版本是16.13.1) 好的,废话不多说,我的大侦探们,are you ready ? 让咱们开启明天的揭秘之旅把。 案件一:组件莫名其妙反复挂载接到报案之前的一位同学遇到一个诡异状况,他心愿在组件更新,componentDidUpdate执行后做一些想要做的事,组件更新源来源于父组件传递 props 的扭转。然而父组件扭转 props发现视图渲染,然而componentDidUpdate没有执行,更怪异的是componentDidMount执行。代码如下: // TODO: 反复挂载class Index extends React.Component{ componentDidMount(){ console.log('组件初始化挂载') } componentDidUpdate(){ console.log('组件更新') /* 想要做一些事件 */ } render(){ return <div>《React进阶实际指南》 { this.props.number } + </div> }}成果如下 componentDidUpdate没有执行,componentDidMount执行,阐明组件基本没有走更新逻辑,而是走了反复挂载。 逐个排查子组件一头雾水,基本不找起因,咱们只好从父组件动手。让咱们看一下父组件如何写的。 const BoxStyle = ({ children })=><div className='card' >{ children }</div>export default function Home(){ const [ number , setNumber ] = useState(0) const NewIndex = () => <BoxStyle><Index number={number} /></BoxStyle> return <div> <NewIndex /> <button onClick={ ()=>setNumber(number+1) } >点赞</button> </div>}从父组件中找到了一些端倪。在父组件中,首先通过BoxStyle做为一个容器组件,增加款式,渲染咱们的子组件Index,然而每一次通过组合容器组件造成一个新的组件NewIndex,真正挂载的是NewIndex,水落石出。 ...

June 6, 2021 · 7 min · jiezi

关于react.js:react源码解析3react源码架构

react源码解析3.react源码架构视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 这一章的目标是让咱们认识一下react源码架构和各个模块。 在真正的代码学习之前,咱们须要在大脑中有一个react源码的地图,晓得react渲染的大抵流程和框架,这样能力从上帝视角看react是怎么更新的,来吧少年。 react的外围能够用ui=fn(state)来示意,更具体能够用 const state = reconcile(update);const UI = commit(state);下面的fn能够分为如下一个局部: Scheduler(调度器): 排序优先级,让优先级高的工作先进行reconcileReconciler(协调器): 找出哪些节点产生了扭转,并打上不同的Flags(旧版本react叫Tag)Renderer(渲染器): 将Reconciler中打好标签的节点渲染到视图上一图胜千言: jsxjsx是js语言的扩大,react通过babel词法解析(具体怎么转换能够查阅babel相干插件),将jsx转换成React.createElement,React.createElement办法返回virtual-dom对象(内存中用来形容dom阶段的对象),所有jsx实质上就是React.createElement的语法糖,它能申明式的编写咱们想要组件呈现出什么样的ui成果。在第5章jsx咱们会具体介绍jsx解析之后的后果。 Fiber双缓存Fiber对象下面保留了包含这个节点的属性、类型、dom等,Fiber通过child、sibling、return(指向父节点)来造成Fiber树,还保留了更新状态时用于计算state的updateQueue,updateQueue是一种链表构造,下面可能存在多个未计算的update,update也是一种数据结构,下面蕴含了更新的数据、优先级等,除了这些之外,下面还有和副作用无关的信息。 双缓存是指存在两颗Fiber树,current Fiber树形容了以后出现的dom树,workInProgress Fiber是正在更新的Fiber树,这两颗Fiber树都是在内存中运行的,在workInProgress Fiber构建实现之后会将它作为current Fiber利用到dom上 在mount时(首次渲染),会依据jsx对象(Class Component或的render函数者Function Component的返回值),构建Fiber对象,造成Fiber树,而后这颗Fiber树会作为current Fiber利用到实在dom上,在update(状态更新时如setState)的时候,会依据状态变更后的jsx对象和current Fiber做比照造成新的workInProgress Fiber,而后workInProgress Fiber切换成current Fiber利用到实在dom就达到了更新的目标,而这一切都是在内存中产生的,从而缩小了对dom好性能的操作。 例如上面代码的Fiber双缓存构造如下,在第7章会具体解说 function App() { const [count, setCount] = useState(0); return ( <> <h1 onClick={() => { // debugger; setCount(() => count + 1); }} > <p title={count}>{count}</p> xiaochen </h1> </> )}ReactDOM.render(<App />, document.getElementById("root")); ...

June 2, 2021 · 2 min · jiezi

关于react.js:react源码解析2react的设计理念

react源码解析2.react的设计理念视频课程(高效学习):进入课程课程目录:1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录构造和调试 5.jsx&外围api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.context 18事件零碎 19.手写迷你版react 20.总结&第一章的面试题解答 21.demo 异步可中断React15慢在哪里在讲这部分之前,须要讲是那些因素导致了react变慢,并且须要重构呢。 React15之前的协调过程是同步的,也叫stack reconciler,又因为js的执行是单线程的,这就导致了在更新比拟耗时的工作时,不能及时响应一些高优先级的工作,比方用户的输出,所以页面就会卡顿,这就是cpu的限度。 解决方案如何解决这个问题呢,试想一下,如果咱们在日常的开发中,在单线程的环境中,遇到了比拟耗时的代码计算会怎么做呢,首先咱们可能会将工作宰割,让它可能被中断,在其余工作到来的时候让出执行权,当其余工作执行后,再从之前中断的局部开始异步执行剩下的计算。所以要害是实现一套异步可中断的计划。 实现在方才的解决方案中提到了工作宰割,和异步执行,并且能让出执行权,由此能够带出react中的三个概念 Fiber:react15的更新是同步的,因为它不能将工作宰割,所以须要一套数据结构让它既能对应实在的dom又能作为分隔的单元,这就是Fiber。 let firstFiberlet nextFiber = firstFiberlet shouldYield = false//firstFiber->firstChild->siblingfunction performUnitOfWork(nextFiber){ //... return nextFiber.next}function workLoop(deadline){ while(nextFiber && !shouldYield){ nextFiber = performUnitOfWork(nextFiber) shouldYield = deadline.timeReaming < 1 } requestIdleCallback(workLoop)}requestIdleCallback(workLoop)Scheduler:有了Fiber,咱们就须要用浏览器的工夫片异步执行这些Fiber的工作单元,咱们晓得浏览器有一个api叫做requestIdleCallback,它能够在浏览器闲暇的时候执行一些工作,咱们用这个api执行react的更新,让高优先级的工作优先响应不就能够了吗,但事实是requestIdleCallback存在着浏览器的兼容性和触发不稳固的问题,所以咱们须要用js实现一套工夫片运行的机制,在react中这部分叫做scheduler。Lane:有了异步调度,咱们还须要细粒度的治理各个工作的优先级,让高优先级的工作优先执行,各个Fiber工作单元还能比拟优先级,雷同优先级的工作能够一起更新,想想是不是更cool呢。产生进去的下层实现 因为有了这一套异步可中断的机制,咱们就能实现batchedUpdates批量更新和Suspense 上面这两张图就是应用异步可中断更新前后的区别,能够领会一下 代数效应(Algebraic Effects)除了cpu的瓶颈问题,还有一类问题是和副作用相干的问题,比方获取数据、文件操作等。不同设施性能和网络情况都不一样,react怎么去解决这些副作用,让咱们在编码时最佳实际,运行利用时体现统一呢,这就须要react有拆散副作用的能力,为什么要拆散副作用呢,因为要解耦,这就是代数效应。 发问:咱们都写过获取数据的代码,在获取数据前展现loading,数据获取之后勾销loading,假如咱们的设施性能和网络情况都很好,数据很快就获取到了,那咱们还有必要在一开始的时候展现loading吗?如何能力有更好的用户体验呢? 看下上面这个例子 function getPrice(id) { return fetch(`xxx.com?id=${productId}`).then((res)=>{ return res.price })}async function getTotalPirce(id1, id2) { const p1 = await getPrice(id1); const p2 = await getPrice(id2); return p1 + p2;}async function run(){ await getTotalPrice('001', '002'); }getPrice是一个异步获取数据的办法,咱们能够用async+await的形式获取数据,然而这会导致调用getTotalPrice的run办法也会变成异步函数,这就是async的传染性,所以没法拆散副作用。 ...

June 1, 2021 · 2 min · jiezi

关于react.js:react16-版本源码-简单分析2

首先 我这里 有一份配置好的 react源码配置 地址如下 仓库 地址 git地址:git@github.com:544076724/react16-source.git 下载下来间接 yarn start启动就能够了前言:react我的项目是基于Monorepo 构造开发的,后续文章中所呈现的地址都是咱们工程的src/react/packages/ 这一级来找的具体包 接下来咱们简略做下剖析 咱们这篇外面临时不波及太多的优先级工作,react源码里的优先级工作 是通过计算一个过期工夫来计算的 他们本人实现的一套算法 这里临时不介绍这个算法 大家晓得这个优先级算法是requestIdleCallback的欠缺版 就能够 咱们晓得后面说了fiber构造 而fiber的构造是由vnode 转换过去的,JSX 被 Babel 编译为 React.createElement 办法的调用,createElement 办法在调用后返回的就是 ReactElement,就是 virtualDOM。 createElement文件地位:packages/react/src/ReactElement.js /** * 创立 React Element * type 元素类型 * config 配置属性 * children 子元素 * 1. 拆散 props 属性和非凡属性 * 2. 将子元素挂载到 props.children 中 * 3. 为 props 属性赋默认值 (defaultProps) * 4. 创立并返回 ReactElement */export function createElement(type, config, children) { /** * propName -> 属性名称 * 用于前面的 for 循环 */ let propName; /** * 存储 React Element 中的一般元素属性 即不蕴含 key ref self source */ const props = {}; /** * 待提取属性 * React 外部为了实现某些性能而存在的属性 */ let key = null; let ref = null; let self = null; let source = null; // 如果 config 不为 null if (config != null) { // 如果 config 对象中有非法的 ref 属性 if (hasValidRef(config)) { // 将 config.ref 属性提取到 ref 变量中 ref = config.ref; // 在开发环境中 if (__DEV__) { // 如果 ref 属性的值被设置成了字符串模式就报一个提醒 // 阐明此用法在未来的版本中会被删除 warnIfStringRefCannotBeAutoConverted(config); } } // 如果在 config 对象中领有非法的 key 属性 if (hasValidKey(config)) { // 将 config.key 属性中的值提取到 key 变量中 key = '' + config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; // 遍历 config 对象 for (propName in config) { // 如果以后遍历到的属性是对象本身属性 // 并且在 RESERVED_PROPS 对象中不存在该属性 if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { // 将满足条件的属性增加到 props 对象中 (一般属性) props[propName] = config[propName]; } } } /** * 将第三个及之后的参数挂载到 props.children 属性中 * 如果子元素是多个 props.children 是数组 * 如果子元素是一个 props.children 是对象 */ // 因为从第三个参数开始及当前都示意子元素 // 所以减去前两个参数的后果就是子元素的数量 const childrenLength = arguments.length - 2; // 如果子元素的数量是 1 if (childrenLength === 1) { // 间接将子元素挂载到到 props.children 属性上 // 此时 children 是对象类型 props.children = children; // 如果子元素的数量大于 1 } else if (childrenLength > 1) { // 创立数组, 数组中元素的数量等于子元素的数量 const childArray = Array(childrenLength); // 开启循环 循环次匹配子元素的数量 for (let i = 0; i < childrenLength; i++) { // 将子元素增加到 childArray 数组中 // i + 2 的起因是实参汇合的前两个参数不是子元素 childArray[i] = arguments[i + 2]; } // 如果是开发环境 if (__DEV__) { // 如果 Object 对象中存在 freeze 办法 if (Object.freeze) { // 调用 freeze 办法 解冻 childArray 数组 // 避免 React 外围对象被批改 解冻对象进步性能 Object.freeze(childArray); } } // 将子元素数组挂载到 props.children 属性中 props.children = childArray; } /** * 如果以后解决是组件 * 看组件身上是否有 defaultProps 属性 * 这个属性中存储的是 props 对象中属性的默认值 * 遍历 defaultProps 对象 查看对应的 props 属性的值是否为 undefined * 如果为undefined 就将默认值赋值给对应的 props 属性值 */ // 将 type 属性值视为函数 查看其中是否具备 defaultProps 属性 if (type && type.defaultProps) { // 将 type 函数下的 defaultProps 属性赋值给 defaultProps 变量 const defaultProps = type.defaultProps; // 遍历 defaultProps 对象中的属性 将属性名称赋值给 propName 变量 for (propName in defaultProps) { // 如果 props 对象中的该属性的值为 undefined if (props[propName] === undefined) { // 将 defaultProps 对象中的对应属性的值赋值给 props 对象中的对应属性的值 props[propName] = defaultProps[propName]; } } } /** * 在开发环境中 如果元素的 key 属性 或者 ref 属性存在 * 监测开发者是否在组件外部通过 props 对象获取了 key 属性或者 ref 属性 * 如果获取了 就报错 */ // 如果处于开发环境 if (__DEV__) { // 元素具备 key 属性或者 ref 属性 if (key || ref) { // 看一下 type 属性中存储的是否是函数 如果是函数就示意以后元素是组件 // 如果元素不是组件 就间接返回元素类型字符串 // displayName 用于在报错过程中显示是哪一个组件报错了 // 如果开发者显式定义了 displayName 属性 就显示开发者定义的 // 否者就显示组件名称 如果组件也没有名称 就显示 'Unknown' const displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; // 如果 key 属性存在 if (key) { // 为 props 对象增加key 属性 // 并指定当通过 props 对象获取 key 属性时报错 defineKeyPropWarningGetter(props, displayName); } // 如果 ref 属性存在 if (ref) { // 为 props 对象增加 ref 属性 // 并指定当通过 props 对象获取 ref 属性时报错 defineRefPropWarningGetter(props, displayName); } } } // 返回 ReactElement return ReactElement( type, key, ref, self, source, // 在 Virtual DOM 中用于辨认自定义组件 ReactCurrentOwner.current, props, );}ReactElement/** * 接管参数 返回 ReactElement */const ReactElement = function (type, key, ref, self, source, owner, props) { const element = { /** * 组件的类型, 十六进制数值或者 Symbol 值 * React 在最终在渲染 DOM 的时候, 须要确保元素的类型是 REACT_ELEMENT_TYPE * 须要此属性作为判断的根据 */ $$typeof: REACT_ELEMENT_TYPE, /** * 元素具体的类型值 如果是元素节点 type 属性中存储的就是 div span 等等 * 如果元素是组件 type 属性中存储的就是组件的构造函数 */ type: type, /** * 元素的惟一标识 * 用作外部 vdom 比对 晋升 DOM 操作性能 */ key: key, /** * 存储元素 DOM 对象或者组件 实例对象 */ ref: ref, /** * 存储向组件外部传递的数据 */ props: props, /** * 记录以后元素所属组件 (记录以后元素是哪个组件创立的) */ _owner: owner, }; // 返回 ReactElement return element;};该办法波及到的 一些辅助函数 也都在这个文件中 大家能够下载下来源代码 而后看一下 ...

May 29, 2021 · 22 min · jiezi

关于react.js:chrome浏览器插件react-devtoolsredux-devtools无需安装解压即可用

react devtools用于调试react代码,能够查看到props、state的值,以及定义的hooks,而redux devtools能够追踪到action的派发、store的变动,两个都是react开发过程中十分好用的工具! 上面是附上两个开发者工具下载地址 react devtools 链接:https://pan.baidu.com/s/1gLF1Bw9vn6CRiWnFayfJYA 提取码:shskredux devtools链接:https://pan.baidu.com/s/1FI7RU3vQ1raEXpmQ-fwXUA 提取码:in0n下载文件后解压 关上拓展程序,抉择 加载已解压的拓展程序,导入下面的文件夹 导入文件夹后就能够在拓展程序里看到 react 和redux的开发者工具 点击右上角的用户旁相似于 拼图 的按钮,将react、redux开发者工具固定在导航栏处,如果该页面应用了react / redux,对应的图标会变亮,生产环境和开发环境亮的色彩不一样,如果没有应用则置灰 而后通过 ctrl + shift + i,查看/审查元素,当该页面有应用react / redux 时,能力找到 react / redux 的开发者工具,抉择即可进行相干的调试 以上就是react/redux的开发者工具装置步骤

May 28, 2021 · 1 min · jiezi

关于react.js:React-生命周期

React 生命周期(旧) react旧版生命周期蕴含三个过程: 1、挂载过程constructor()componentWillMount()componentDidMount() 2、更新过程componentWillReceiveProps(nextProps)shouldComponentUpdate(nextProps,nextState)componentWillUpdate (nextProps,nextState)render()componentDidUpdate(prevProps,prevState) 3、卸载过程componentWillUnmount() 其具体作用别离为:1、constructor()实现了React数据的初始化。 2、componentWillMount()组件曾经实现初始化数据,然而还未渲染DOM时执行的逻辑,次要用于服务端渲染。 3、componentDidMount()组件第一次渲染实现时执行的逻辑,此时DOM节点曾经生成了。 4、componentWillReceiveProps(nextProps)接管父组件新的props时,从新渲染组件执行的逻辑。 5、shouldComponentUpdate(nextProps, nextState)在setState当前,state发生变化,组件会进入从新渲染的流程时执行的逻辑。在这个生命周期中return false能够阻止组件的更新,次要用于性能优化。 6、componentWillUpdate(nextProps, nextState)shouldComponentUpdate返回true当前,组件进入从新渲染的流程时执行的逻辑。 7、render()页面渲染执行的逻辑,render函数把jsx编译为函数并生成虚构dom,而后通过其diff算法比拟更新前后的新旧DOM树,并渲染更改后的节点。 8、componentDidUpdate(prevProps, prevState)从新渲染后执行的逻辑。 9、componentWillUnmount()组件的卸载前执行的逻辑,比方进行“革除组件中所有的setTimeout、setInterval等计时器”或“移除所有组件中的监听器removeEventListener”等操作。 React生命周期(新) react16.4后应用了新的生命周期,应用getDerivedStateFromProps代替了旧的componentWillReceiveProps及componentWillMount。应用getSnapshotBeforeUpdate代替了旧的componentWillUpdate。 应用getDerivedStateFromProps(nextProps, prevState)的起因:旧的React中componentWillReceiveProps办法是用来判断前后两个 props 是否雷同,如果不同,则将新的 props 更新到相应的 state 下来。在这个过程中咱们实际上是能够拜访到以后props的,这样咱们可能会对this.props做一些奇奇怪怪的操作,很可能会毁坏 state 数据的繁多数据源,导致组件状态变得不可预测。 而在 getDerivedStateFromProps 中禁止了组件去拜访 this.props,强制让开发者去比拟 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在依据以后的 props 来更新组件的 state,而不是去拜访this.props并做其余一些让组件本身状态变得更加不可预测的事件。 应用getSnapshotBeforeUpdate(prevProps, prevState)的起因:在 React 开启异步渲染模式后,在执行函数时读到的 DOM 元素状态并不总是渲染时雷同,这就导致在 componentDidUpdate 中应用 componentWillUpdate 中读取到的 DOM 元素状态是不平安的,因为这时的值很有可能曾经生效了。 而getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是能够保障与componentDidUpdate 中统一的。

May 28, 2021 · 1 min · jiezi

关于react.js:React-SSR

意识SSR1.为什么须要SSR呢?单页面富利用的局限: 之前咱们开发的应用程序,如果右键间接查看源代码,能够看到下面简直没有什么内容然而咱们为什么能够看到大量的内容呢?因为当咱们申请下来动态资源之会执行JS,JS会去申请数据,并且渲染咱们想看到的 然而这个过程存在两个问题: 问题一:首屏显示速度较慢问题二:不利于SEO优化如何解决这个问题呢? 应用服务端渲染2.意识SSRSSR(Server Side Rendering,服务端渲染),指的是页面在服务器端曾经生成了实现的HTML页面构造,不须要浏览器解析对应的是CSR(Client Side Rendering,客户端渲染),咱们开发SPA页面通常依赖的就是客户端渲染晚期的服务端渲染包裹PHP、JSP、ASP等形式,然而在目前 "前后端拆散" 的开发模式下,前端开发人员不太可能再去学习PHP、 JSP等技术来开发网页不过咱们能够借助于Node来帮忙咱们执行JavaScript代码,提前完成页面的渲染 3.同构什么是同构?一套代码既能够在服务端又能够在客户端运行,这就是同构利用;同构是一种SSR的状态,是现带SSR的一种表型模式;当用户发出请求时,先在服务器通过SSR渲染出首页的内容;然而对应的代码同样在能够在客户端执行;执行的目标包含事件绑定等以及其它页面切换时也能够在客户端被渲染;冀望在服务器上拿到html页面并发送申请,之后的的后果间接响应给客户端之前是由浏览器执行的-》当初由node.js来实现 index.html 1.申请js文件 2.执行js文件 3.ajax 申请 4.继续执行js遍历数据,生成html构造Next.js1.应用React SSR应用React SSR次要有两种形式: 形式一: 手动搭建一个SSR框架;形式二: 应用曾经成熟的SSR框架: Next.js装置Next.js框架的脚手架: npm install -g create-next-app创立Next.js我的项目 create-next-app next-demopackage.json文件↓ 2.首页的展现Next.js默认曾经给咱们配置好了路由映射关系:门路和组件的映射关系;这个映射关系就是在pages中配置相干的组件都会主动生成对应的门路;默认page/index.js是页面的默认门路: 3.对于页面和页面跳转定义About页面 从Home页面跳转到About页面 4.Layout组件咱们发现home和about是两个互相独立的组件: 如果他们有一些公共的内容: 比方头部、尾部都是一样的,是否每个中央都须要写一遍呢?有两种解决方案: 计划一: 自定义一个Layout的组件,将公共的内容放到Layout中;计划二: 在 _app 中编写公共局部的内容; 5.Next.js反对各种款式形式一: 全局款式引入形式二: module.css形式三: 默认集成styled-jsx<style>{` p { color: #f879c6; }`}</style>形式四: 其余css in js计划,比方 styled-components styled-components在Next服务器上渲染的的问题: 组件应用了styled-components显示是没有问题的,这是在客户端进行渲染的,然而只有咱们手动刷新,className就不进行匹配,这是因为在服务端渲染和在客户端渲染的className不匹配如何解决:引入相干依赖,创立和编辑 .babelrc 文件yarn add styled-componentsyarn add -D babel-plugin-styled-components编辑 .babelrc 文件{ "presets": [ "next/babel" ], "plugins": [ ["styled-components"] ]}6.路由的补充路由的嵌套(子路由): ...

May 27, 2021 · 1 min · jiezi

关于react.js:前端导出Excel在线指北

Hello, 各位怯懦的小伙伴, 大家好, 我是你们的嘴强王者小五, 身体健康, 脑子没病. 自己有丰盛的脱发技巧, 能让你一跃成为资深大咖. 一看就会一写就废是自己的宗旨, 菜到抠脚是自己的特点, 低微中透着一丝丝坚强, 傻人有傻福是对我最大的刺激. 欢送来到小五的随笔系列之前端导出Excel在线指北. 写在后面双手奉上代码链接 传送门 - ajun568 双脚奉上最终效果图 观前揭示 本文最终实现成果如上图, 具体性能为: 导出Excel + 多个Sheet + 可合并的多行表头. 代码局部采纳 React+TS 作为工具进行编写. 筹备工作 装置 xlsx.js npm install xlsx 写入Excel文件: XLSX.write(workbook, writeOpts) workbook SheetNames @types string[]: 以后 Sheet 的名称Sheets: 以后sheet的对象, 格局如下[SheetNames]: { "!refs": "A1:G7", // 示意从 第1行第A列 到 第7行第G列 "!cols": [{wpx: 80} ... ], // 示意 列宽 80px "!rows": [{hpx: 20} ... ], // 示意 行高 20px "!merges": [{s: {r: 0, c: 2}, e: {r: 0, c: 3}} ... ], // 示意 将 第0行第2列 和 第0行第3列 进行合并 (s: start, e: end, c: column, r: row) "A1": {v: "姓名"}, // 示意第1行第A列 显示数据为 "姓名", 以此类推 ... ...}writeOpts ...

May 26, 2021 · 2 min · jiezi