React的起源和发展
React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。
React与传统MVC的关系
轻量级的视图层库!A JavaScript library for building user interfaces
React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。可以简单地理解为,React 将将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。
React高性能的体现:虚拟DOM
React高性能的原理:
原因:
web开发中需要将变化的数据实时反应到UI(视图)上 ,需要DOM操作,然而频繁的DOM操作会导致严重的性能问题, 因此React为此引入了虚拟DOM(Virtual DOM)的机制
什么是 虚拟DOM(Virtual DOM)机制
待补充~~
React的虚拟DOM算法
react 16以前:和vue一样采用diff算法
react 16以后:采用 React Fiber
React Fible的原理
React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
React的特点和优势
虚拟DOM
组件系统
单项数据流
JSX语法
React起步
组件:
- 函数式组件:
function App() {
return (
<div className="App">
<p>我是函数式组件</p>
</div>
);
}
- class组件:
import React,{ Component } from 'react'
class Home extends React.Component{
render () {
return (
<div className="App">
<p>我是函数式组件</p>
</div>
)
}
}
- 组件的组合和嵌套
import React from 'react'
import {Fragment} from 'react'
class A extends React.Component{
render () {
return (
<div>A</div>
)
}
}
class B extends React.Component{
render () {
return (
<div>B</div>
)
}
}
class Detail extends React.Component{
render () {
return (
<Fragment>
<A></A>
<B></B>
</Fragment>
)
}
}
export default Detail
Detail组件里嵌套了A组件和B组件
Fragment的作用
- 代替唯一根元素,并且不会被渲染
- 不会生成外层的元素
JSX原理
要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构?
看下面的DOM结构
<div class='app' id='appRoot'>
<h1 class='title'>欢迎进入React的世界</h1>
<p>
React.js 是一个帮助你构建页面 UI 的库
</p>
</div>
上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示:
{
tag: 'div',
attrs: { className: 'app', id: 'appRoot'},
children: [
{
tag: 'h1',
attrs: { className: 'title' },
children: ['欢迎进入React的世界']
},
{
tag: 'p',
attrs: null,
children: ['React.js 是一个构建页面 UI 的库']
}
]
}
但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。
于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
下面代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
<div className='app' id='appRoot'>
<h1 className='title'>欢迎进入React的世界</h1>
<p>
React.js 是一个构建页面 UI 的库
</p>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
编译之后将得到这样的代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
React.createElement(
"div",
{
className: 'app',
id: 'appRoot'
},
React.createElement(
"h1",
{ className: 'title' },
"欢迎进入React的世界"
),
React.createElement(
"p",
null,
"React.js 是一个构建页面 UI 的库"
)
)
)
}
}
ReactDOM.render(
React.createElement(App),
document.getElementById('root')
)
React.createElement` 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为
React.createElement(
type,
[props],
[...children]
)
所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()
—>DOM元素 —>插入页面
组件内的DOM样式
- 行内样式
想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:
// 注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号
<p style={{color:'red', fontSize:'14px'}}>Hello world</p>
行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如render
函数里、组件原型上、外链js文件中
- class样式
平常我们用的是class但在react里class应该写为className
<p className="hello" style = {this.style}>Hello world</p>
- 不同的条件添加不同的样式
有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classnames这个包:
- css-in-js
styled-components
是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接
组件的数据挂载方式
属性(props)
props正常是外部传入的,
组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 props
属性是描述性质、特点的,组件自己不能随意更改。
class Title extends Component {
render () {
return (
<h1>欢迎进入{this.props.name}的世界</h1>
)
}
}
class App extends Component {
name="React"
render () {
return (
<Fragment>
<Title name="React" />
</Fragment>
)
}
}
props.children
我们知道使用组件的时候,可以嵌套。要在自定义组件的使用嵌套结构,就需要使用 props.children
。在实际的工作当中,我们几乎每天都需要用这种方式来编写组件。
然而,当父组件这样使用子组件时:(使用子组件时在子组件双标签里写了东西)
class App extends Component {
render () {
return (
<Fragment>
<Title>React</Title>
<Content><i>React.js</i>是一个构建UI的库</Content>
</Fragment>
)
}
}
这种情况页面中不会显示子组件的内容,会被React.js是一个构建UI的库替换掉,name我们如何解决呢???
答案:子组件中使用props.children
class Title extends Component {
render () {
return (
<h1>欢迎进入{this.props.children}的世界</h1>
)
}
}
const Content = (props) => {
return (
<p>{props.children}</p>
)
}
使用prop-types验证props
生产环境使用
npm i prop-types -S
引入
import PropTypes from 'prop-types'
组件Child里使用
Child.propTypes={//属性验证
name: PropTypes.number
}