前言:如果只愿意做松轻的事,人生就会困难重重;而果如你愿意做困难的事,那么人生就会变得轻松。为什么?
前置技能:
- React 开发前置技能 使用 VS Code 搭建 TypeScript 开发环境_cao919的专栏-CSDN博客
- javaScript进阶 ES6 详细全解,解构赋值,Proxy,箭头函数,class类, 模块,export和import,Promise,then 方法,async等等_cao919的专栏-CSDN博客
- 前端 webpack 4 打包工具_cao919的专栏-CSDN博客_前端打包工具
------------------
react教程
1. 背景介绍
React 是什么?
React 起源于Facebook的内部项目。2013年开源供给大家使用是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
React的声明式特点减少了操作DOM的性能损耗,同时组件化开发使得大量的组件得以复用。内部实现的虚拟DOM和DOM diff算法使DOM的操作变得高效。
React 特点
-
1.声明式设计 −React采用声明范式,可以轻松描述应用。
-
2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
-
3.灵活 −React可以与已知的库或框架很好地配合。
-
4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。
-
5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
-
6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,也维护的数据安全性
虚拟DOM
虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,例如你连续的先将节点内容从A变成B,然后又从B变成A,React会认为UI不发生任何变化。
CDN引入React
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
使用CDN方式引入的时候,script片段代码需要申明type为text/babel
JSX语法
直接写在 JavaScript 语言之中的HTML 语言就是JSX。JSX,是一种 JavaScript 的语法扩展,它允许 HTML 与 JavaScript 的混写。JSX是facebook为React框架开发的一套语法糖
const dom = <h1>Hello, world!</h1>;
你可以任意地在 JSX 当中使用 JavaScript 表达式,在 JSX 当中的表达式要包含在大括号里。
const name = 'Tina'; const element = ( <div> Hello, {name}! </div> );
JS语法
react提供了一个createElement方法创建虚拟DOM,方法接收3个参数,第一个参数是标签名,第二是标签属性,第三个是标签内容。
const dom = React.createElement('h1','','hello,word!')
2.项目搭建
使用脚手架创建项目
npx是webpack的运行工具
npm install -g create-react-app create-react-app my-app cd my-app npm start
添加路由库 react-router-dom
npm i react-router-dom
3.组件
一个应用/版块/页面中用于实现某个局部的功能(包括html, js, css等)把这些局部功能组装到一起,就形成了组件
在react里,组件的最小颗粒度是一个标签元素
1.无状态组卷 2.有状态组件
创建组件
-
用函数定义组件
function HelloMessage(props) { return <h1>Hello World!</h1>; }
-
使用Class定义组件
class HelloMessage extends React.Component { render() { return <h1>Hello World!</h1>; } }
4.State状态
React 把组件看成是一个状态机。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
在React中,我们可以在组件(Class定义的组件)里添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {name: 'World'}; } render() { return <h1>Hello {this.state.name}!</h1>; } }
更改组件的name属性,即可更改页面渲染结果
class HelloMessage extends React.Component { constructor(props) { super(props); this.state = {name: 'World'}; } nameChange(){ this.setState({ name:'Tina' }) } render() { return <div> <h1>Hello {this.state.name}!</h1> <button onClick={()=>{this.nameChange()}}>变身</button> </div>; } }
5.事件绑定
React 元素的事件处理和 DOM 元素类似。但是有一点语法上的不同:
-
React 事件绑定属性的命名采用驼峰式写法,而不是小写。
-
如果采用 JSX 的语法你需要传入一个函数作为事件处理函数
<button onClick={()=>{this.tick()}}> 增加 </button>
在通过Class创建的组件内,想要使用this调用函数,可以在构造函数内bind this对象为当前this,也可以在绑定处使用this调用
class App extends React.Component{ constructor(props){ super(props) this.state = { age:this.props.age } this.ageChange = this.ageChange.bind(this); } ageChange(){ this.setState({ age:this.state.age+1 }) } render(){ return <div> <span>我今年{this.state.age}岁了</span> <button onClick={()=>{this.ageChange()}}>过年了</button> </div> } }
6.组件props
组件state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。state是组件内部自己定义的,而props是父组件调用时提供的
function HelloMessage(props) { return <h1>Hello {props.name}!</h1>; } const element = <HelloMessage name="Runoob"/>;
通过Class创建的组件,使用this调用props,而在使用之前,需要在类构造函数内,使用super(props)
注入
class HelloMessage extends React.Component { constructor(props){ super(props) } render() { return <h1>Hello {this.props.name}!</h1>; } }
7.条件渲染
在 React 中,可以创建不同的组件来封装各种你需要的行为。然后还可以根据应用的状态变化只渲染其中的一部分。也可以在React 中的使用 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。
const NavTitle=(props)=>{ if(props.type===1){ return <h1>{props.title}</h1> }else if(props.type===2){ return <h2>{props.title}</h2> } }
三目运算
const NavTitle=(props)=>{ return props.type===1?<h1>{props.title}</h1>: <h2>{props.title}</h2> }
8. 列表
react中,可以通过数组生成一系列标准结构组件,通过map
方法完成列表渲染
const numbers = [1, 2, 3, 4, 5]; const listItems = numbers.map((numbers) => <li>{numbers}</li> );
生成原理其实是使listItems
成为一个数组容器,容器内部则是<li>{numbers}</li>
组件,最后react内部可直接展开数组渲染
如果直接将numbers
最为组件,则会展开成为内容被渲染
react在列表渲染的时候需要给组件指定一个key
作为组件的唯一标识,该属性不会作为组件的props被接收,仅供react内部计算使用
Key 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。
9、Refs
React 支持一种非常特殊的属性 Ref ,你可以用来绑定到render() 输出的标签上。
这个特殊的属性允许你引用相应的实例。
<input ref="myInput" /> var input = this.refs.myInput;
引用传递 Forwarding Refs
如果需要给组件绑定ref则上面的方式不支持,react提供了forwardRef
方法来支持组件的引用,引用测方式是用过forwardRef
函数传递ref的引用
const InpuDom= forwardRef((props, ref) => ( <input type="text" ref={ref} /> ));
class ForwardRef extends Component { constructor(props) { super(props); this.ref = createRef(); } componentDidMount() { const { current } = this.ref; current.focus(); } render() { return ( <div> <p>forward ref</p> <InpuDom ref={this.ref} /> </div> ); } }
10.组件生命周期
生命周期的方法有:
-
componentWillMount --在渲染前调用
-
componentDidMount --在第一次渲染后调用
-
componentWillReceiveProps --在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
-
shouldComponentUpdate --返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。(可以在你确认不需要更新组件时使用。)
-
componentWillUpdate --在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
-
componentDidUpdate --在组件完成更新后立即调用。在初始化时不会被调用。
-
componentWillUnmount --在组件从 DOM 中移除之前立刻被调用。
11.组件传值
父组件向子组件传值(自定向下)可以直接使用props
完成
<List ref={this.ref} {...this.state.list[0]}/>
而子组件向父组件传值是自底向上的,这种操作react内部是不支持直接操作的,我们可以选择使用函数props来完成需求
通过在父组件引入的子组件中传递一个函数并传参,子组件去触发这个函数更改参数完成数据更新
子组件
const List = React.forwardRef((props,ref)=>{ const userNameClickFun=(name)=>{ props.getUserName(name) } return <div ref={ref} className="list"> <div onClick={()=>{userNameClickFun(props.name)}} className="left"></div> <div className="right"> <div className="info">{props.name}</div> <div className="text">{props.text}</div> </div> </div> })
父组件
getUserNameFun(name){ console.log(name) } render(){ return <div className="comment-box"> { this.state.list.map(v=><List getUserName={this.getUserNameFun} key={v.id} {...v}/>) } <div className="inp"> <textarea ref="inpDom" onChange={(e)=>{this.getText(e)}}></textarea> <div> <button onClick={()=>{this.subFun()}}>提交评论</button> </div> </div> </div> }
12.高阶组件
如果一个函数操作其他函数,将其他函数作为参数或将函数作为返回值,将其称为高阶函数。高阶组件类似于高阶函数,接收 React 组件作为输入,输出一个新的 React 组件。高阶组件让代码更具有复用性、逻辑性与抽象特征。可以对 render 方法作劫持,也可以控制 props 与 state。
简单来说,高阶组件只是一个包装了另外一个 React 组件的 React 组件。
const NavTitle=(props)=>{ return props.type===1?<h1>{props.title}</h1>: <h2>{props.title}</h2> } const Nav = (props)=>{ if(props.type!=1&&props.type!=2){ return <p>{props.title}</p> }else{ let newPro={ ...props, title:'高阶标题'+props.title } return <NavTitle {...newPro}/> } }
13.Hook
使用函数声明的组件大多数为无状态组件,展示型组件一般是无状态组件
Hook是供给函数组件进行状态管理的方法,只能在 React 的函数组件中调用 Hook
State Hook
通过useState
申明一个值为0的变量,并且同时可以获得一个可以更改当前变量的方法,通过setCount
方法修改的count可以同时更新页面。等价Class组件的state
和setState
function Example() { // 声明一个叫 "count" 的 state 变量 const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Effect Hook
useEffect简单理解就是监听函数组件中的数据。是componentDidMount
,componentDidUpdate
和 componentWillUnmount
这三个函数的组合
useEffect(() => { document.title = `You clicked ${count} times`; });