网址
React 官方中文文档 – 用于构建用户界面的 JavaScript 库
一、了解:
用于构建用户界面的 JavaScript 库
-
声明式:
React 使创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据改变时 React 能有效地更新并正确地渲染组件。
以声明式编写 UI,可以让你的代码更加可靠,且方便调试。
-
组件化:
创建拥有各自状态的组件,再由这些组件构成更加复杂的 UI。
组件逻辑使用 JavaScript 编写而非模板,因此你可以轻松地在应用中传递数据,并使得状态与 DOM 分离。
-
一次学习,随处编写:
无论你现在正在使用什么技术栈,你都可以随时引入 React 来开发新特性,而不需要重写现有代码。
React 还可以使用 Node 进行服务器渲染,或使用 React Native 开发原生移动应用。
二、入门案例
-
使用react脚手架create-react-app搭建react环境
-
安装脚手架
选择一个文件夹,运行如下命令
npx create-react-app reacte-basic
-
启动命令
cd reacte-basic
npm start
三、从0开始编写react程序
-
删除src下的所有文件
-
src下创建index.js入口文件
测试代码console.log("hello react")
console.log('hello react')
页面运行后,输出了hello react,
index.js为整个react项目的js入口文件
-
在index.js中实现react程序
import React from "react" import ReactDom from "react-dom" //reactDom渲染组件 ReactDom.render( <div><h1>hello</h1></div>,// 组件 document.getElementById("root") // 将组件挂载到public/index.html的root元素中 )
四、创建自定义组件
-
src/pages/Header.jsx
// import React from "react" // //使用类并通过继承React下的Component类 创建组件 // class Header extends React.Component { // } // 也可以在引入react时直接解构Component // 注 :Component为抽象类,需要实现render方法 import React,{ Component } from "react" class Header extends Component { render() { //方法返回组件 return <div>hello</div> } } // 暴露Header模块 export default Header
-
index.js中使用Header组件,自定义组件使用时要首字母大写,与html标签区分
import React from "react" import ReactDom from "react-dom" // 引入Header组件 import Header from "./pages/Header" //reactDom渲染组件 ReactDom.render( <Header></Header>,// 使用Header组件 document.getElementById("root") // 将组件挂载到public/index.html的root元素中 )
五、react的起源与发展:
React起源于Facebook的内部项目,因为该公司对市场上所有javaScript MVC框架,都不够满意,决定自己写一套,用来架设Instagram的网站,从2011年开始研发,做出来以后,发现这套东西很好用,就在2013年5月开源了。
六、React与传统的MVC的关系
轻量级的视图层库!A javaScript library for building user Interfaces
React不是一个完整的MVC框架,最多可以说是MVC中的V(View),甚至React并不非常认可MVC开发模式;
React构建页面UI的库,可以简单地理解为,React将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就构成了我们的页面。
七、React高性能的体现:虚拟DOM
7.1 React高性能原理
在Web开发中我们总需要 将变化的数据实时反应到UI上,这时就需要对DOM进行操作,而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。
React为此引入了虚拟DOM(Virtaual DOM)的机制,在浏览器端用javaScript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据发生变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B,B-A,React会认为A变成B,然后又从B变成A,UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。
尽管每一次都需要构造完成虚拟DOM树,但是因为harnDOM是内存数据,性能是极高的。而对实际的DOM进行操作的仅仅是Diff部分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在做任意一个数据状态下,整个界面是如何Render的。
7.2 React Fiber:
在react 16之后发布的一种react核心算法,React Fiber是对核心算法的一次重新实现(官网的说法)。之前用的是diff算法。
在之前的React中,更新过程是同步的,这可能会导致性能问题。
当React决定要加载或者更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual Dom,最后更新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者更新过程开始,中途不会中断。因为javaScript单线程的特点,如果组件树很大的时候,每个同步任务耗时太长,就会出现卡顿。
React Fiber的方法其实很简单--分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其它任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。
八、React的特点和优势
8.1 虚拟DOM
我们以前操作DOM的方式是通过document.getElementById()等方式,这样的过程实际上是先去读取html的DOM结构,将结构转换成变量,再进行操作。
而reactjs定义了一套变量形成的DOM模型,一切操作和换算直接在变量中,这样减少了操作真实DOM,性能真实相当高,和主流MVC框架有本质的区别,并不和DOM直接打交道。
8.2 组件系统
react最核心的具备了你就将页面中任何一个区域或者元素都可以看做一个组件component
那么什么是组件呢?
组件指的就是同时包含了html、css、js、image元素的聚合体
使用react开发的核心就是将页面拆分成若干个组件,并且react一个组件中同时耦合了css、js、image,这种模式整个颠覆了过去的传统方式
8.3 单向数据流
其实reactjs的核心内容就是数据绑定,所谓数据绑定指的是只要将一些服务端的数据和前端页面绑定好,开发者只关注实现业务就行了。
8.4 JSX语法
在vue中,我们使用render函数来构建组件的DOM结构性能较高,因为省去了查找 和编译模板的过程,但是在render中利用createElement创建结构的时候代码可读性较低,较为复杂,此时可以利用jsx语法来在render中创建dom,解决这个问题,但是前提是需要使用工具来编译jsx
九、组件分类:
9.1 类组件
import React,{ Component } from "react"
class Header extends Component { //使用类的方式创建的组件
render() {
//方法返回组件
return <div>hello</div>
}
}
// 暴露Header模块
export default Header
9.2 函数式组件 (缺点:无法设置状态)
定义一个Footer组件 src/pages/Footer.jsx
// 组件中一定要引入React才不会出错
import React from "react"
function Footer(){
return <div>Footer</div>
}
export default Footer
index.js中使用组件
// 解构Fragment,类似于vue中的template模板组件
import React,{ Fragment } from "react"
import ReactDom from "react-dom"
// 引入Header组件
import Header from "./pages/Header"
// 引入Footer组件
import Footer from "./pages/Footer"
//reactDom渲染组件
ReactDom.render(
// 需要使用一个容器作为根组件 这里使用React中的Fragment,该组件不被浏览器解析
<Fragment>
<Header></Header>
<Footer></Footer>
</Fragment>,
document.getElementById("root") // 将组件挂载到public/index.html的root元素中
)
这里要注意,当入口中使用了多个组件,多个组件需要使用一个容器包裹,Fragment是React中的一个片段容器,不会被浏览器解析为标签,Fragment在React中也可以直接用‘<></>’空标签代替
import React from "react"
import ReactDom from "react-dom"
// 引入Header组件
import Header from "./pages/Header"
// 引入Footer组件
import Footer from "./pages/Footer"
//reactDom渲染组件
ReactDom.render(
// 空标签代替Fragment
<>
<Header></Header>
<Footer></Footer>
</>,
document.getElementById("root") // 将组件挂载到public/index.html的root元素中
)
9.4 古老的定义组件的方式(不使用es6的class)
文档-高级指引-不使用ES6
可以查阅
-
使用create-react-class插件
-
安装:cnpm i create-react-class -D
-
-
创建组件:src/pages/Nav.jsx
import React from "react" import CreateReacteClass from "create-react-class" const Nav = CreateReacteClass({ render: function() { return <h3>这是导航</h3> } }) export default Nav
-
使用组件:
// 引入Nav导航 import Nav from "./pages/Nav" //reactDom渲染组件 ReactDom.render( // 空标签代替Fragment <> <Nav></Nav> <Header></Header> <Footer></Footer> </>, document.getElementById("root") // 将组件挂载到public/index.html的root元素中 )
十、组件的组合及嵌套
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
十一、jsx原理
要明白jsx的原理,需要行明白如何使用javaScript对象来表现一个DOM元素结构
看下面的dom结构
<div class="app" id="appFoo">
<h1 class="title">欢迎进入react的世界</h1>
<p>
React.js是一个帮助你构建页面UI的库
</p>
</div>
上面这个HTML所有的信息我们都可以用javaScript对象来表示
{
tag:"div",
attrs:{
className:"app",
id:"appFoo"
},
children:[
{
tag:"h1",
attrs:{
className:"title"
},
children:["欢迎进入react的世界"]
},
{
tag:"p",
children:["React.js是一个帮助你构建页面UI的库"]
}
]
}
但是用javascript写起来太长了,结构不看起来又不清晰,用HTML的方式写起来就方便很多。
于是React.js就把javascript的语法扩展了一下,让javascript语言能够支持这种直接写在javascript代码里面编写类似HTML标签结构的语法,这样写起来就方便很多,编译的过程会把类似于HTML的jsx结构的转换成js对象结构
如下面的jsx代码:
import React,{ Component } from "react"
class Header extends Component {
render() {
//方法返回组件
return (
<div class="app" id="appFoo">
<h1 class="title">欢迎进入react的世界</h1>
<p>
React.js是一个帮助你构建页面UI的库
</p>
</div>
)
}
}
// 暴露Header模块
export default Header
jsx的语法是使用了React中的createElement语法糖来编译实现js对象的转换,
每个 JSX 元素只是调用 React.createElement(component, props, ...children)
的语法糖。因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。
import { Component,createElement } from "react"
class Header extends Component {
render() {
//不使用jsx方式
//return <div>hello</div>
//直接使用createElement语法糖来完成也是可以的
return (createElement(
"div",
{
id:"app"
},
"headeraaaa"
))
}
}
// 暴露Header模块
export default Header
十二、组件中的DOM样式
12.1 行内样式
想给虚拟DOM添加行内样式,需要使用表达式传入样式对象的方式来实现
import React from "react"
function Footer(){
return (<div style={{background:"blue"}}>Footer</div>)
}
export default Footer
行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如在render函数中,组件原型上,外链js文件中
12.2 使用class
react推荐我们使用行内样式,因为React认为每一个组件都是一个独立的整体,
其实我们大多数情况下还是大量的为元素添加类名,只是class需要写成className(因为毕竟我们的组件是在写js代码,并且是以class类的方式构造,class为创建类的关键字,添加元素类class与js的class有冲突)
render: function() {
return (<h3 className="myNav">这是导航</h3>)
}
render() {
//不使用jsx方式
//return <div>hello</div>
//直接使用createElement语法糖来完成也是可以的
return (createElement(
"div",
{
id:"myDiv",
style:{background:"red"},
className:"myClass"
},
"headeraaaa"
))
}
12.3 不同的条件添加不同的样式
有时需要根据不同的条件添加不同的class,这时推荐使用classnames包
css-in-js
styled-components是针对React写的一套css-in-js框架,简单来说就是在js中写css
-
安装:
cnpm i styled-components -D
-
创建pages/footer.js文件用于编写css
import styled from "styled-components" const FooterWrap = styled.div ` background:yellow ` export { FooterWrap }
-
Footer.jsx中使用footer.js模块
// 组件中一定要引入React才不会出错 import React from "react" // 引入footer.js模块,用于实现css import { FooterWrap } from "./footer.js" function Footer(){ return <FooterWrap>footer</FooterWrap> } export default Footer