1.React是什么?

  React由FaceBook团队2013年5月开源,用来构建UI界面的JavaScript库,相当于MVC中的V层框架,主要采用以下设计思想实现了高效更新视图,最终超越了当时市面上的其它框架,对前端界来说有具有颠覆性的里程碑事件。

React每个组件都有一个状态机概念,组件内部通过state来维护组件自身状态的变化,当状态即State变化时,React通过虚拟化DOM技术来增量,最终用Diff算法技术高效的更新真实原生DOM。

2.Props与State的区别?

   一个组件都同时具有prop和state两个属性特征(即都属于组件的数据),prop与state不要翻译成中文(更难理解),它们经常要搭配使用,都属于组件数据属性,由于React是单向的自下而下的数据流,所以对prop和state的理解,应从父子组件之间关系的角度来理解:

props:用来组件之间传数据,可以是父子组件或者兄弟组件之间。它的特征是只读的即不可修改,另外也可以理解为从外部传入给组件的数据。

state:是组件内部的状态(即组件的内部数据,又称组件私有属性,不能被外部访问或者修改),它的特征是不能直接修改,但可以用setState方法(这个方法是异步的)来改变状态的值,每一次state的变化会导致组件的重新渲染。没有state叫无状态组件,有state叫有状态组件。

props和state的搭配使用:父组件的state可以转化为props传递给子组件,子组件接收到的props是只读的,想要改变值,只能改变父组件的state。

React官方推荐:构建几个无状态组件用来渲染数据,尽量多用无状态组件,所以设计时需要保持组件的单一职责;有状态组件主要用来同用户和服务进行交互,最终通过props传递给无状态组件。

3.React生命周期与生命周期方法

React的生命周期分为三个阶段:挂载、渲染、缷载。每个阶段都有对应若干接口方法,但React15版本和React17版本有一些方法不一样,作废和增加随时React版本的不同而会相应进化。 3.1React15的生命周期方法:

微信图片_20210701130926.png [点击并拖拽以移动]

常用的方法: 挂载与缷载阶段: constructor(): 初始化,写了constructor()必须写super(),否则导致this指向错误。

componentDidMount(): 第一次渲染完成,dom已经生成,这个地方经常用来放异步的ajax调用。

componentWilllUnmount(): 组件的缷载和数据的销毁。

更新阶段: componentWillReceiveProps (nextProps)(新版本已作废): 父组件的props改变后重新渲染组件。

shouldComponentUpdate(nextProps,nextState): 性能优化时用,控制要不要重新渲染。

componentWillUpdate (nextProps,nextState)(新版本已作废): shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,这里同样可以拿到nextProps和nextState。

componentDidUpdate(prevProps,prevState): React只会第一次初始化成功后进入componentDidmount,之后的更新则进入componentDidUpdate。

render(): render函数的jsx生成虚拟的DOM结构,通过diff算法比较前后的新旧DOM树,找到最小差异化的DOM节点后重新渲染页面。 3.2React17的生命周期方法:

作废了render阶段的以下方法,完全可以用componentDidMount代替: componentWillMount componentWillUpdate componentWillReceiveProps

3.2.1 类组件方法:

挂载时顺序 constructor() static getDerivedStateFromProps(props, state)

render() componentDidMount() 更新时顺序 static getDerivedStateFromProps(props, state):getDerivedStateFromProps实际上就是用来取代以前的函数componentWillReceiveProps控制props更新state的过程.

shouldComponentUpdate()

render()

static getSnapshotBeforeUpdate(prevProps, prevState):用于替换 componentWillUpdate,该函数会在update后 DOM 更新前被调用,在最近的更改被提交到DOM元素前,使得组件可以在更改之前获得当前值。 componentDidUpdate() 卸载 componentWillUnmount()

3.2.2 函数式组件方法

通过useState和useEffect hook在不编写class的情况下完成对组件的state管理及其它特性。 4.React的合成虚拟事件系统 4.1 事件的定义:

   事件是编程上来说是一个抽象的概念,可以通俗理解为动作,一个事件通常由“事件、事件源、监听器”三者联合一起工作,一个浏览器有以下一些事件:键盘事件、鼠标事件、触控事件、滚轮事件、剪贴板事件、用户界面事件、焦点事件等。 4.2 事件系统:

   React也自定义了一套事件处理系统,包含了事件监听、事件分发、事件回调等过程,浏览器本身有事件系统接口(我们叫原生事件nativeEvent),react把它重新按自己的标准包装了一下(叫合成事件SyntheticEvent),即大部分合成事件与原生事件的接口是一一对应,但增加为了兼容针对原生的一些不同事件接口进行了合成,目的就是为了使用react工作在不同的浏览器上均兼容,即同时消除了IE与W3C标准实现之间的兼容问题。

React对浏览器本身的事件接口重新包装了一层,它的一些事件可能是原生几个事件的接口的合成,所以叫React合成事件系统。

4.3 React 合成事件系统工作原理

一个事件要工作需分成两个阶段:事件绑定和事件触发。 事件绑定: React提供了一个事件模块,针对不同的事件分别提供了不同的事件插件和一份事件类型索引清单插件,一开始React就把所有合成事件注册初始化成全局对象了。当React diff算法检查Dom需要添加或者更新时,它会检查这个prop是不是一个事件类型,如果是,它根据合成事件类型再检查依赖了哪些原生事件,如果没有注册,则注册到当前的Document上后同时完成对React的回调函数执行即dispatchEvent()。

React的合成事件对于同一个类型的事件,只会绑定一次原生事件,不重复。
React自己捕获事件后自己派发事件回调,即事件委托。
事件触发:
任意一个React事件触发,会执行React的dispatchEvent函数,由它来批量执行已经注册绑定到本Document的事件清单,依次执行对应plugins中的所有事件插件,每个事件插件处理自己的事件。

4.4 React事件处理中为什么需要绑定this?

**官方是这样说的:**你必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。 这并不是 React 特有的行为;这其实与 JavaScript 函数工作原理有关。通常情况下,如果你没有在方法后面添加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this。 **我的理解:**React最新的版本中本身没有(除生命周期的函数外)提供组件实例this自动绑定功能,所以你在用事件函数时,必须人工去绑定this,告诉调用方,你需要把this绑定到你身上(即调用方,又叫中间变量),后面我才知道这个事件属于调用方你的事件。 4.5 React事件如何绑定this?

两种方案:(1)给调用函数时bind(this) (2)箭头函数(即将函数内容返回一个变量),我推荐方法二。 绑定this示例:

import React from 'react'; export default class Life extends React.Component{ constructor(props){ super(props); this.state = { count:1 }; } render(){ return ( <div>
<button onClick={this.handleAdd}>无bind点击事件绑定this</button> <button onClick={this.handleClick.bind(this)}>有bind点击事件绑定this</button> <p>{this.state.count}</p> </div> ) } //此时this指向是当前实例对象 handleAdd = ()=> { console.log(this) this.setState({ count:2 }) } handleClick(){ console.log(this) this.setState({ count:3 }) } }

[点击并拖拽以移动]

1.

5.React条件判断渲染的用法

这一块没有vue的v-if用起来省事,但可能更灵活。 React的条件渲染和JavaSrcipt中的一样,使用JavaScript本身的运算符if或者条件运算会去创建元素来表现当前的状态,然后让React根据它们来更新UI。 **if运算符: ** if (布尔值变量) {}; 与运算符&&:   通过花括号包裏代码,在JSX中嵌入任何表达式,JavaScript中,true&&exession总是返回expression,而false&&expression总是会返回false.

{unreadMessages.length > 0 && <h2> You have {unreadMessages.length} unread messages. </h2> } </div> ); }

三目运算符: JavaScript 中的三目运算符 condition ? true : false。

render() { const isLoggedIn = this.state.isLoggedIn; return ( <div> The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div> ); }

阻止组件的渲染(即隐藏某一个组件): 这一块没有vue的v-show使用方便,但有时候也可能更灵活。 render方法返回一个null,而让它不进行任何渲染,例如:

function WarningBanner(props) { if (!props.warn) { return null; }

return ( <div className="warning"> Warning! </div> ); } 调用方组件: render() { return ( <div> <WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}> {this.state.showWarning ? 'Hide' : 'Show'} </button> </div> ); } }

[点击并拖拽以移动] 6.React循环渲染的用法

React没有vue中的v-for标签功能,它用JavaScript的Map()来实现循环,例如:

<ul> {this.state.goods.map( good => <li key={good.id}>{good.text}</li> )} </ul>

[点击并拖拽以移动] 7.编写一个React组件的代码基本框架

在写React组件建议用ES6和ES7语法。 7.1 类组件代码结构:React Class

import React from 'react'; class MyComponent extends React.Component { constructor(props) { super(props); ... } state = { count: 0 } componentnentWillMount () { } componentDidMount () { } componentWillReceiveProps (nextProps) { } shouldComponentUpdate (nextProps,nextState) { } componentWillUpdate (nextProps,nextState) { } componentDidUpdate (prevProps,prevState) { } componentWillUnmount () { } // 箭头函数省得绑定事件了,函数体内的this指向的对象是定义时所在的对象,而不是使用时所在的对象 handleChange = ()=> { this.setState({count: this.state.count + 1}); } render() { return ( <div> <h2>当前计数是:{this.state.count}</h2> <button onClick={this.handleChange}>点击 </button> </div> ); } } export default MyComponent;

主要约定规范:

  • 类的名字就是组件的名字,首字母大写(大驼峰命名法)
  • 类要继承React.Component
  • 类内部一定要有render函数,否则报错

7.2 函数组件代码结构(据于Hooks,重点推荐用这个):Function Component

hook没有this,它主要通用useState来初始化,useEffect处理原生命周期函数(componentDidMount 和componentDidUpdate以及componentWillUnmount 三个的结合)。 // 接口声明部分.... // React.FC表示Function Component的缩写,是函数组件,这里面没有生命周期的函数定义,可以定义useState,useEffect等hook. const TableList: React.FC = () => { // useState语法 const [ state, setState ] = useState( initialState ) //useEffect的语法为:   useEffect(() => {   doSomething   }, [input])

return ( <div>....</div> );

}; export default TableList;

[点击并拖拽以移动] 8.React State共享

全局共享: umijs 的插件:@umijs/plugin-initial-state和@umijs/plugin-model 搭配一起用。

多个组件之间共享: useContext hook实现。 父子组件共享: 状态提升法,提到共同的父组件中,采用传参法。 9.React的组合与继承用法

FaceBook团队建议不用继承,只用组合,即多提炼子组件,这些组件组合在一起形成页面组件。 ​