React
一、React基础
1.React概述
1.1 什么是React
-
官方文档 -
React是一个用于构建用户界面的JavaScript库
-
React主要是用来写HTML页面,或者构建Web应用 -
如果从MVC的角度来说,React仅仅是视图层,也就是只负责视图的渲染,而并非提供了完整的M,C的功能
1.2React的特点
2.React基础使用
2.1React的安装
npm i react react-dom
- react 包是核心,提供创建元素、组件等功能
- react-dom 包提供DOM相关功能等
2.2React的使用
-
引入react和react-dom <script src="./node_modules//react/umd/react.development.js"></script>
<script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
-
创建React元素 const title=React.createElement('h1',null,'HelloWorld!')
React.createElement(img,{src:'xxx',style:'width:200px;'},'HelloWorld!')
-
渲染React元素到页面中 ReactDOM.render(title,document.getElementById('root'))
3.React脚手架的使用
3.1使用React脚手架初始化项目
- 初始化项目
npx create-react-app 项目名称
- npx 是 npm v5.2.0 引入的一条命令
- 可以提升包内提供的命令行工具的使用体验
- 启动项目
npm start
3.2在脚手架中使用React
-
导入react 和 react-dom两个包 import React from 'react'
import ReactDOM from 'react-dom'
-
调用 React.createElement()方法创建react元素 -
调用 ReactDOM.render()方法渲染元素到页面中
二、JSX
1.JSX的基本使用
1.1 createElement()的问题
- 繁琐不简洁
- 不直观,不能从代码中轻易的看出结构
- 不优雅
1.2 JSX简介
- JSX 是 JavaScript XML的简写,表示在JavaScript代码中写**XML(HTML)**格式的代码。
- 优势:
- 声明式语法更加直观
- 与HTML结构相同,降低了学习成本
- 提升开发效率
1.3使用步骤
1.4为什么React脚手架中可以使用JSX语法
- JSX不是标准的ECMAScript语法,它是ECMAScript的语法扩展
- 需要使用babel编译处理后,才能在浏览器环境中使用
- React脚手架中默认已经帮我们配置好了babel相关的配置,无需手动配置
- 编译JSX语法的包为:@babel/preset-react
1.5注意事项
- React元素的属性名使用驼峰命名法
- class —> className for —> htmlFor tabindex —> tabIndex
- 没有子节点的React元素可以用 />结束
- 推荐 :使用小括号包裹JSX,从而避免JS中自动插入分号陷阱
2.JSX中使用JavaScript表达式
const test='haha'
const title = (
<h1>HelloWorld! {test}</h1>
)
ReactDOM.render(title,document.getElementById('root'))
3.JSX的条件渲染
const show=(n)=>{
if(n===1) return <p>n是1</p>
else return <p>n不是1</p>
}
const title = (
<div>
<h2>{show(1)}</h2>
</div>
)
ReactDOM.render(title,document.getElementById('root'))
4.JSX的列表渲染
const p = [
{name:'张三',age:'18'},
{name:'罗老师',age:'不知道'}
]
const test = (
<div>
<ul>
{p.map(item=> <li>{item.name}---{item.age}</li>)}
</ul>
</div>
)
ReactDOM.render(test,document.getElementById('root'))
5.JSX的样式处理
import './index.css'
const test = (
<div>
<p style={{color:"red", fontSize:"30px"}}>你好</p>
<p className='test'>你好</p>
</div>
)
ReactDOM.render(test,document.getElementById('root'))
三、组件基础
1.React组件介绍
- 非常重要
- 组件表示页面中的部分功能
- 组合多个组件实现完整的页面功能
- 特点
2.React组件的两种创建方式
-
使用函数创建组件
-
函数组件:使用函数(普通函数,箭头函数均可)创建的组件 -
约定1:函数名称必须以大写字母开头 -
约定2:函数组件必须有返回值,表示该组件结构 -
如果返回值为null,表示不渲染任何内容 -
const Test = ()=>(
<div>
<p style={{color:"red", fontSize:"30px"}}>你好</p>
<p>你好</p>
</div>
)
ReactDOM.render(<Test/>,document.getElementById('root'))
-
使用类创建组件
-
类组件:使用ES6中的class创建的组件 -
约定1:类名称首字母大写 -
约定2:类组件应该继承React.Component父类,从而可以使用父类中提供的方法或者属性 -
约定3:类组件必须提供**render()**方法 -
约定4:render()方法必须有返回值,表示该组件结构 -
class Test extends React.Component {
render(){
return (
<div>
<p style={{color:"red", fontSize:"30px"}}>你好</p>
<p>你好</p>
</div>
)
}
}
ReactDOM.render(<Test/>,document.getElementById('root'))
-
抽离组件到单独js文件中
-
创建js文件 -
在文件中导入React -
创建组件 -
暴露组件 -
import React from 'react'
export default class Test extends React.Component {
render(){
return (
<div>
<p style={{color:"red", fontSize:"30px"}}>你好</p>
<p>你好</p>
</div>
)
}
}
import Test from './components/Test'
ReactDOM.render(<Test/>,document.getElementById('root'))
3.React事件处理
-
语法:on+事件名称={事件处理函数} -
注意:React事件采用驼峰命名法,如:onMouseEnter,onFocus -
export default class Test extends React.Component {
render(){
return (
<div>
<button onClick={this.testClick}>点我一下</button>
</div>
)
}
testClick(){
alert('点我干嘛!')
}
}
-
事件对象
4.有状态组件和无状态组件
- 函数组件 ====> 无状态组件
- 类组件 ====> 有状态组件
5.组件中的state和setState()
6.事件绑定this指向
-
箭头函数 -
Function.prototype.bind()方法 constructor(){
super()
this.test=this.test.bind(this)
}
-
class的实例方法
add=()=>{
this.setState({n:this.state.n+1})
}
7.表单处理
7.1受控组件
-
将表单元素的value值交给state管理 -
受控组件:其值受到React控制的表单元素 -
使用 export default class Test extends React.Component {
state={
mes:''
}
render(){
return (
<div>
<input type="text" value={this.state.mes} onChange={e => this.setState({mes:e.target.value})}/>
</div>
)
}
}
-
多个表单优化 export default class Test extends React.Component {
state={
mes:'',
isChecked:false
}
render(){
return (
<div>
{}
<input type="text" name="mes" value={this.state.mes} onChange={this.change}/>
<br/>
同意:<input type="checkbox" name="isChecked" checked={this.state.isChecked} onChange={this.change}/>
</div>
)
}
change=e=>{
let newvalue
if(e.target.type==='checkbox')newvalue=e.target.checked
else newvalue=e.target.value
this.setState({[e.target.name]:newvalue})
}
}
7.2非受控组件(DOM方式)(不推荐)
四、组件进阶
1.组件的props
2.组件通信的三种方式
- 父组件 ==> 子组件
- 父组件提供要传递的数据(state)
- 给子组件标签添加属性,值为state中的数据
- 子组件通过props接收父组件传递的数据
- 子组件 ==> 父组件
- 父组件向子组件传递一个回调函数,回调函数的参数为需要接收的数据
- 子组件调用父组件传递的回调函数,将数据传递给父组件
- 兄弟组件间
- 状态提升:将共享的状态(即数据)提升到最近的公共父组件中,由公共的父组件管理这个状态
- 公共的父组件提供数据及操作数据的方法
- 子组件只需要通过接收数据或者调用方法去传递或者接收数据
3.Context
-
作用:跨组件传递数据 -
使用
-
调用 React.createContext()创建Provider(提供数据) 和Consumer(消费数据)两个组件 const {Provider,Consumer}=React.createContext()
-
使用Provider组件作为父节点 <Provider value={data}> {/*将要传递的数据通过Provider标签的value属性传递*/}
<div className="App">
<Child1/>
</div>
</Provider>
-
使用Consumer组件接收数据 <Consumer>
{data => <p>{data}</p>} {/*接收数据*/}
</Consumer>
4.props深入
5.组件的生命周期
5.1概述
- 意义:有助于理解组件的运行方式、完成更加复杂的组件功能、分析组件错误原因等
- 组件的生命周期:组件从被创建到挂载到页面中运行,再到组件不再用时卸载的过程
- 生命周期钩子:生命周期中某一个重要阶段会有一些方法的调用,这些方法就叫做生命周期钩子
- 生命周期钩子,为开发人员在不同阶段操作组件提供了时机
- 只有类组件才有生命周期!
5.2生命周期的三个阶段
React组件生命周期官方图示
6.render-props和高阶组件
五、React原理
1.setState()说明
-
setState更新数据是异步的!!!!!!!!!!! -
避免更新数据直接依赖上次更新后的数据 -
连续多次调用setState(),只会触发一次页面重新渲染 -
推荐语法:setState((state,props)=>{})
this.setState((state,props)=>{
return {
}
})
-
setState有第二个参数,参数是一个回调函数,这个函数会在状态更新完成后立即执行。
2.JSX语法的转换过程
- JSX实际上是createElement()方法的语法糖
- JSX被@babel/preset-react插件编译为createElement()
- createElement()会把内容转化为React元素(是一个对象,用来描述界面内容)
3.组件更新机制
4.组件性能优化
-
减轻state:只存储跟组件相关的数据 -
避免不必要的重新渲染
- 使用钩子函数 shouldComponentUpdate(nextProps,nextState) 返回值为bool,true:需要更新,flase:不需要更新
-
纯组件(pureComponent)
5.虚拟DOM和Diff算法
- 只要状态改变,就重新更新视图
- 虚拟DOM:本质上就是JS对象,用来描述你希望在屏幕上看到的内容(UI)
- Diff算法:
- 初次渲染时,React会根据state(Model),创建一个虚拟DOM对象(树)
- 根据虚拟DOM生成真正的真实DOM,渲染到页面中
- 当状态发送改变的时候,更新新的数据,创建新的虚拟DOM对象(树)
- 根据diff算法,找到需要更新的地方,更新真实DOM
六、React路由
1.路由的基本使用
-
安装 react-router-dom : npm i react-router-dom -
在index.js中引入BrowserRouter import {BrowserRouter} from 'react-router-dom' -
用BrowserRouter组件将整个应用包裹起来 <BrowserRouter>
<App />
</BrowserRouter>
- 两种常用的Router:
- HashRouter:使用URL的哈希值实现 (不美观,不优雅,有/#/)
- BrowserRouter:使用H5的historyAPI实现
-
引入Link ,Routes,Route import { Link,Routes,Route } from "react-router-dom" -
添加Link <Link to="/test">test</Link> (最终会解析成a标签)
-
添加Routes及Route <Routes>
<Route path="/" element={<App />} /> {/*path为'/'表示默认路由*/}
<Route path="/test" element={<Test />} />
<Route
path="*" {/*path为'*'表示其它未定义路由404 No Found*/}
element={
<main style={{ padding: "1rem" }}>
<p>404 No Found!</p>
</main>
}
/>
</Routes>
2.路由嵌套
<Routes>
<Route path="/" element={<App />}>
<Route index path="expenses" element={<Expenses />} /> {/*index 属性,让子级路由设为默认路由*/}
<Route path="invoices" element={<Invoices />} />
</Route>
</Routes>
//自适应渲染组件Outlet
//在App组件中
export default function App() {
return (
<div>
<nav>
<Link to="/invoices">Invoices</Link>
<Link to="/expenses">Expenses</Link>
</nav>
<Outlet /> {/*根据路径决定渲染哪个组件*/}
</div>
);
}
3.路由传参
3.1 useParams
-
通过path传递参数 <Route path=":invoiceId" element={<Invoice />} /> -
接收参数 import { useParams } from "react-router-dom"
export default function Invoice() {
let params = useParams()
return <h2>Invoice: {params.invoiceId}</h2>
}
3.2 useSearchParams
-
传递参数 <Route path="/test?id=1&num=2" element={<Test />} /> -
接收参数 import { useSearchParams } from "react-router-dom"
export default function Test() {
let [searchParams, setSearchParams] = useSearchParams();
let id=searchParams.get('id')
let num=searchParams.get('num')
}
setSearchParams({id:1,num:2})
4.编程式路由及其传参
-
使用useNavigate钩子进行路由跳转及传递参数 import {useNavigate} from 'react-router-dom'
let navigate=useNavigate()
const test =() =>{
navigate("/test",{state:{
id:1,
num:2
}})
}
-
使用useLocation接收参数 import {useLocation} from 'react-router-dom'
let location=useLocation()
let {id,num} = location.state
5.常用组件及钩子
组件名 | 作用 | 说明 |
---|
<Routers> | 一组路由 | 代替原有<Switch> ,所有子路由都用基础的Router children来表示 | <Router> | 基础路由 | Router是可以嵌套的,解决原有V5中严格模式,后面与V5区别会详细介绍 | <Link> | 导航组件 | 在实际页面中跳转使用 | <Outlet/> | 自适应渲染组件 | 根据实际路由url自动选择组件 |
hooks名 | 作用 | 说明 |
---|
useParams | 返回当前参数 | 根据路径读取参数 | useNavigate | 返回当前路由 | 代替原有V5中的 useHistory | useOutlet | 返回根据路由生成的element | | useLocation | 返回当前的location 对象 | | useRoutes | 同Routers组件一样,只不过是在js中使用 | | useSearchParams | 用来匹配URL中?后面的搜索参数 | |
|