react学习
Posted 暑假过期le
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react学习相关的知识,希望对你有一定的参考价值。
React
React的特点
1.采用组件化模式,声明式编码,提高开发效率及组件复用率
2.在React Native中可以使用React语法进行移动端开发
3.使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互
虚拟DOM和真实DOM的差别
虚拟dom:
1.本质式object类型的对象(一般对象)
2.虚拟dom比较‘轻’,真实dom比较‘重’,因为虚拟dom是react内部使用,无需真实dom这么个那么多的属性
3.虚拟dom最终会被react转化为dom,呈现在页面上
扩展:debugger 断点
jsx语法规则
jsx语法规则:
1.定义虚拟dom的时候,不用写引号
2.标签中混入js表达式的时候用{}
3.样式的类名指定不要用class,要用className
4.内联样式,要用style={{key:value}}的形式去写
5.只有一个根标签
6.标签必须闭合 单标签可以写成
7.标签首字母
- 如果小写字母开头,则将该标签转为html中的同名元素,如果html标签中没有同名元素报错
- 如果大写字母开头,react就去渲染对用的组件,如果没有定义组件,报错
区分 js语句(代码)与js表达式
表达式:一个表达式会产生一个值,可以放在任何一个需要的地方
- a
- a+b
- six(1)
- arr.map()
- function text(){}
语句(代码)
- if{}
- for{}
- switch(){case:…}
函数式组件写法
类式组件写法
复杂组件和简单组件
简单组件是没有状态的
复杂组件是有状态的
ref的作用
Context(解决层级出现多的情况如爷爷传递给孙子)
使用步骤
- 调用 React.createContext() 创建 Provider(提供数据) 和 Consumer(消费数据) 两个组件
const {Provider,Consumer} = React.createContext()
使用Provider组件作为组件的父节点
那一层想要接受父节点传来的数据用Consumer进行包裹,在里面回调函数中的参数就是传递过来的值
props校验
常见的约束规则
-
创建的类型: array、bool、func、number、object、string
-
React元素类型: element
-
必填项: isRequired
-
特定结构的对象: shape({})
生命周期阶段(常用的钩子)
创建时(挂在阶段)
-
执行时机:组件创建时(页面加载时)
-
执行顺序
-
触发时机
-
钩子函数 触发时机 作用 constructor 创建组件时,最先执行 1.初始化state 2.为事件处理程序绑定this render 每次页面渲染时都会触发 渲染UI(注意不能调用setState()) componentDidMount 组件挂载(完成dom渲染)后 1.发网络请求 2 .DOM操作 更新时
- 执行时机:setState() forceUpdate() ,组件接收到新的props
- 说明以上三者任意一种变化,组件就会重新渲染
- 执行顺序
钩子函数 | 触发时机 | 作用 |
---|---|---|
render | 每次组件渲染都会触发 | 渲染UI |
componentDidUpdate | 组件更新(完成dom渲染)后 | 1.发送网络请求2.DOM操作 注意:如果要setState()必须放在一个if条件中 |
卸载时
- 执行时机:组件从页面中消失
- 作用:用来做清理操作
钩子函数 | 触发时机 | 作用 |
---|---|---|
componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作(比如:清理定时器等) |
Diff算法
执行过程
- 初次渲染时,React会根据初始化的state(model),创建一个虚拟dom的对象(树)
- 根据虚拟DOM生成真正的DOM,渲染到页面
- 当数据变化后(setState()),会重新根据新的数据,创建新的虚拟DOM对象(树)
- 与上一次得到的虚拟DOM对象,使用Diff算法比对(找不同),得到需要更新的内容
- 最终,React只将变化的内容更新(patch)到DOM中,重新渲染到页面
路由的基本使用
安装:
npm install --save react-router-dom
导入路由的三个核心组件: Router / Route / Link
import {BrowserRouter as Router, Route, Link} from 'react-router-dom'
使用Router 组件包裹整个应用
使用Link组件作为导航菜单(路由入口)
常用组件说明
-
Router组件:包裹整个应用,一个React应用只需要使用一次
-
两种常用的Router: HashRouter和BrowserRouter
-
HashRouter: 使用URL的哈希值实现 (localhost:3000/#/first)
-
推荐 BrowserRouter:使用H5的history API实现(localhost3000/first)
-
Link组件:用于指定导航链接(a标签)
-
最终Link会编译成a标签,而to属性会被编译成 a标签的href属性
-
Route组件:指定路由展示组件相关信息
-
path属性:路由规则,这里需要跟Link组件里面to属性的值一致
-
component属性:展示的组件
-
Route写在哪,渲染出来的组件就在哪
编程式导航
- 场景:点击登陆按钮,登陆成功后,通过代码跳转到后台首页,如何实现?
- 编程式导航:通过JS代码来实现页面跳转
- history是React路由提供的,用于获取浏览器历史记录的相关信息
- push(path):跳转到某个页面,参数path表示要跳转的路径
- go(n):前进或后退功能,参数n表示前进或后退页面数量
const Second = (props) => {
function gotoPage () {
props.history.push('/first')
}
return (<div>
<p>页面二</p>
<button onClick={gotoPage.bind(this)}>First</button>
</div>
)
}
精准匹配
-
给Route组件添加exact属性,让其变为精准匹配模式
-
精确匹配:只有当path和pathname完全匹配时才会展示改路由
组件性能优化
避免不必要的重新渲染
- 组件更新机制:父组件更新会引起子组件也被更新
- 问题:子组件没有任何变化值也会重新渲染
- 解决方法:使用钩子函数 shouldComponentUpdate(nextProps, nextState)
- 这个函数中nextProps和nextState是最新的状态以及属性
- 作用:这个函数有返回值,如果返回true,代表需要重新渲染,如果返回false,代表不需要重新渲染
- 触发时机:更新阶段的钩子函数,组件重新渲染执行((shouldComponentUpdate => render)
纯组件
作用以及使用
- 纯组件: PureComponent 与 React.Component 功能相似
- 区别: PureComponent 内部自动实现了 shouldComponentUpdate钩子,不需要手动比较
- 原理:纯组件内部通过分别比对前两次 props 和state的值。来决定知否重新渲染组件
组件复用
使用步骤
- 创建Mouse组件,在组建中提供复用的逻辑代码
- 将要复用的状态作为 props.render(state)方法的参数,暴露到组件外部
- 使用props.render() 的返回值作为要渲染的内容
class Mouse extends React.Component {
// 鼠标位置状态
state = {
x: 0,
y: 0
}
// 监听鼠标移动事件
componentDidMount () {
window.addEventListener('mousemove', this.handleMouseMove)
}
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render () {
// 向外界提供当前子组件里面的数据
return this.props.render(this.state)
}
}
class App extends React.Component {
render () {
return (
<div>
App
<Mouse render={mouse => {
return <p>X{mouse.x}</p>
}} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
推荐使用Children代替上面的的方法
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
class Mouse extends Component {
// 鼠标位置状态
state = {
x: 0,
y: 0
}
// 监听鼠标移动事件
componentDidMount () {
window.addEventListener('mousemove', this.handleMouseMove)
}
handleMouseMove = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render () {
// 向外界提供当前子组件里面的数据
return this.props.children(this.state)
}
}
class App extends Component {
render () {
return (
<div>
<h1>鼠标移动</h1>
<Mouse >
{({ x, y }) => <p>鼠标位置:{y}</p>}
</Mouse>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
总结:
- render-props 是通过为组件添加 render 属性的方式传递一个函数给子组件,供子组件调用
- children,可以实现 render-props 的功能,区别是将函数通过子组件的内容传递过来,但是 chlldren 更加强大,可以传递任意的数据给子组件
高阶组件(HOC)
使用步骤
- 创建一个函数,名称约定以with开头
- 指定函数参数,参数应该以大写字母开头
- 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
- 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
- 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面
包装函数
// 定义一个函数,在函数内部创建一个相应类组件
function withMouse (WrappedComponent) {
// 该组件提供复用状态逻辑
class Mouse extends React.Component {
state = {
x: 0,
y: 0
}
// 事件的处理函数
handleMouseMove = (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 当组件挂载的时候进行事件绑定
componentDidMount () {
window.addEventListener('mousemove', this.handleMouseMove)
}
// 当组件移除时候解绑事件
componentWillUnmount () {
window.removeEventListener('mousemove', this.handleMouseMove)
}
render () {
// 在render函数里面返回传递过来的组件,把当前组件的状态设置进去
return <WrappedComponent {...this.state} />
}
}
return Mouse
}
哪个组件需要加强,通过调用 withMouse 这个函数,然后把返回的值设置到父组件中即可
function Position (props) {
return (
<p>
X:{props.x}
Y:{props.y}
</p>
)
}
// 把position 组件来进行包装
let MousePosition = withMouse(Position)
class App extends React.Component {
constructor(props) {
super(props)
}
render () {
return (
<div>
高阶组件
<MousePosition></MousePosition>
</div>
)
}
}
以上是关于react学习的主要内容,如果未能解决你的问题,请参考以下文章
javascript 用于在节点#nodejs #javascript内设置react app的代码片段
[React Testing] Use Generated Data in Tests with tests-data-bot to Improve Test Maintainability(代码片段