IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React学习笔记 -> 正文阅读

[JavaScript知识库]React学习笔记

一、组件三大属性

每个组件的this上都有三个重要属性:

  1. state
  2. props
  3. refs

1.state

state称为状态,状态驱动着页面的改变

class Person extends Component {
    
    state = {
        name="张三",
        age:18
    }
	
	/*
	 此处必需写箭头函数
	 不然按钮处就需要写this.change.bind(this),确保this不丢失
	*/
	change=()=>{
        /*
        更新状态是合并,不是覆盖,即传入参数{name:"李四"}
        与原装胎对比,不会覆盖原状态中的age
        */
        this.state({name:"李四"})
    }
	
    render() {
        return (
            <div>
				{<span>{this.state.name}</span>}
                <button onClick={this.change}>点我更新状态</button>
            </div>
        )
    }
}

2.props

父组件传递给子组件的参数

class Father extends Component {
    state = {
        bear:{
            x:1,
            y:2
        }
    }

    render() {
        return (
            <div>
                <Child x={1} y={2}></Child>
            </div>
        )
    }
}

/*
或者:
将bear对象结构,得到x,y,相当于分别传递
<Child {...this.state.bear}></Child>
*/

子组件中可对接收到的参数进行限制,需引入React库中的PropTypes进行限制

//npm i prop-types

import PropTypes from 'prop-types'

class Child extends Component {
    //静态属性
    static propTypes={
        //支持链式写法
        x:PropTypes.string.isrequired
        //类型以小写开头,以区别原生,如:string,object,bool
        //ps:函数类型:func
    }
	
	//默认值
	static defaultProps={
        x:1
    }

    render() {
        return (
            <div>
				{this.props.x}
            </div>
        )
    }
}

/*
或者:
Child.propTypes={
	x:PropTypes.func
}
*/

3.refs

使用ref可直接拿到组件的原生DOM对象

//有三种写法获得ref

//1.字符串式(不推荐)
class Person extends Component {
	
    render() {
        console.log(this.refs)
        return (
            <div>
				<span ref="demo"></span>
            </div>
        )
    }
}

//2.回调函数式
class Person extends Component {
	/*
	  函数式会将ref作为参数传递给回调函数,即c,
      可直接写在类实例属性上,即this.test=c,
      这样可不用去refs里取
    */
    render() {
        return (
            <div>
				<span ref={c=>{this.test=c}}></span>
            </div>
        )
    }
}

二、生命周期

旧生命周期

image-20210723201728475

初始化

  1. constructor(构造函数)
  2. componentWillMount(将要挂载)
  3. render(渲染函数)
  4. componentDidMount(组件已经挂载)

更新时

  1. shouldComponentUpdate(控制是否更新)
  2. componentWillUpdate(组件将要更新)
  3. render(渲染函数)
  4. componentDidUpdate(组件已经更新)

卸载时

可由ReactDOM.unmountComponentAtNode()手动触发组件卸载

  1. componentWillUnmount(组件将要卸载)

注意

  • shouldComponentUpdate控制是否允许此次更新,返回true则允许更新,继续后面流程,返回false则中断后面流程,不返回值则报错。
  • 组件上的forceUpdate()方法,可强制更新,跳过shouldComponentUpdate控制。

新生命周期

image-20210723202250778

初始化

在constructor和render之间加入getDerivedStateFromProps钩子,用法比较罕见,一般在state全受prop控制时使用,以下摘自官网:

image-20210723202747080

更新时

同初始化时,在shouldComponentUpdate前加入钩子:getDerivedStateFromProps,不过还在componentDidUpdate前加入,getSnapshotBeforeUpdate(更新前获得组件快照),用法也比较罕见,以下摘自官网:

image-20210723203020329

卸载时

同旧的生命周期钩子。

即将废弃的钩子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

使用会出现警告,最好不使用,或者前面带上UNSAFE_前缀来使用。

总结

新的生命周期相交于旧的

废弃了三个不重要的钩子:将要挂载,将要收到参数,将要更新

更新了两个罕见的钩子:获得props驱动的state,更新前获得组件快照

总的来说,重要的钩子有三个:

  1. render,渲染函数
  2. componentDidMount,组件挂载完成,一般做发起请求,初始化等工作。
  3. componentWillUnmount,组件即将卸载,一般做收尾工作。

三、React原理简述

React组成

  1. react.js,React核心库。
  2. react-dom.js,提供操作DOM的react核心库,依赖于上述库。
  3. babel.js,用于解析jsx,将其转换为js代码的库。

Vitual Dom和Diff算法

相较于直接操作较大的真实(与虚拟相对)DOM对象,操作JS里的对象可优化浏览器性能,减少重排和重绘的次数。

故将真实的浏览器DOM对象映射成JS里的对象(虚拟DOM),每次数据更新,驱动视图的改变时,查看虚拟DOM有没有受影响,未受影响,则复用,否则重新渲染。

//每个dom都有一个key值,用以区分每个虚拟DOM

class Person extends Component {
    state = {
        arr=[
        	{id:1,name:'老张',age:30},
        	{id:2,name:'老王',age:20}
        ]
    }

    render() {
        //此处key值不推荐(不是不可以)使用数组下标index
        const {arr}=this.state
        return (
            <ul>
				arr.map((item,index)=>{
                    return <li key={index}>{item.name}-{item.age}</li>
                })
            </ul>
        )
    }

	/*
		 render() {
        //此处key值不推荐使用数组下标index
        若dom中有一些"未改变"(要复用的DOM)(若正好是输入类,则很危险)
        则一些破坏原数组,如:逆序插入
        的方法可能导致每个li和input错位
        const {arr}=this.state
        return (
            <ul>
				arr.map((item,index)=>{
                    return <li key={index}> {item.name}-{item.age} <input/></li>
                })
            </ul>
        )
    }

	*/
}

四、Router路由

1.实现原理

SPA(Single Page APP)

  1. 只有一个完整页面
  2. 点击页面中的链接,不会刷新页面,只会做局部更新

原生实现

通过监听Window上的Hash或History的变化,来实现页面的更新,如下:

		//方法一,直接使用H5推出的history身上的API
		// let history = History.createBrowserHistory() 
		//方法二,hash值(锚点)
		let history = History.createHashHistory() 
		
        //历史记录压栈
		function push (path) {
			history.push(path)
			return false
		}
		
   		//替换掉栈顶的历史记录
		function replace (path) {
			history.replace(path)
		}
		
		//历史记录后退
		function back() {
			history.goBack()
		}
		
		//历史记录前进
		function forword() {
			history.goForward()
		}

		history.listen((location) => {
			console.log('请求路由路径变化了', location)
		})

前进和后退对应浏览器URL左边的:image-20210723205406125

2.使用

react-router-dom提供组件:

  • BrowserRouter、HashRouter,一般包在APP组件外边,决定是哪种路由方式。
  • Route 注册路由
  • Redirect 重定向
  • Link、NavLink、Switch 决定路由跳转

例一:Route和Switch的使用

入口文件:

//引入react核心库
import React from 'react'
//引入ReactDOM
import ReactDOM from 'react-dom'
//引入BrowserRouer路由组件
import { BrowserRouter } from 'react-router-dom'
//引入App
import App from './App'

ReactDOM.render(
	<BrowserRouter>
		<App />
	</BrowserRouter>,
	document.getElementById('root')
)

App:

import React, { Component } from 'react'
import {NavLink,Route} from 'react-router-dom'
import Home from './pages/Home' //Home是路由组件
import About from './pages/About' //About是路由组件
import Header from './components/Header' //Header是一般组件

export default class App extends Component {
	render() {
		return (
			<div>
				<div>
					<div>
						<Header/>
					</div>
				</div>
				<div>
					<div>
						<div>
							{/*类似于原生中的a标签 */}
							<NavLink to="/about">About</NavLink>
							<NavLink to="/home">Home</NavLink>
						</div>
					</div>
					<div>
						<div>
							<div>
								{/* 注册路由 */}
								<Route path="/about" component={About}/>
								<Route path="/home" component={Home}/>
							</div>
						</div>
					</div>
				</div>
			</div>
		)
	}
}

NavLink和Link差别:NavLink可给activeClassName,activeStyle等属性

Switch作用:只渲染一个匹配到的第一个路由,不会渲染多个,如下:

//若无Switch包裹,当路径为/home时以下三个组件皆渲染
<Route path="/home" component={Home}/>
<Route path="/:user" component={User}/>
<Route component={NoMatch}/>

//包裹起来确保只渲染匹配到的第一个
<Switch>
	<Route path="/home" component={Home}/>
	<Route path="/:user" component={User}/>
	<Route component={NoMatch}/>
</Switch>

例二:精准匹配和模糊匹配

//路由导航
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home/a/b">Home</MyNavLink>

//注册路由
<Switch>
    <Route exact path="/"      component={Root} />
	<Route exact path="/about" component={About}/>
	<Route exact path="/home"  component={Home}/>
</Switch>

**exact表示开启路由精准匹配,**如:路径/home/a/b必需精准对应某个路由的path,该路由才能进行渲染。

Route默认是模糊匹配,如:路由Root的path是/home/a/b的字串,匹配上了,优先进行渲染;若未使用Switch组件,则Root和Home一并渲染。

工程中一般都是模糊匹配

例三:重定向

<Switch>
	<Route path="/home" component={Home}/>
	<Route path="/about" component={About}/>
	<Redirect to="/about" />
</Switch>

重定向组件一般对路由进行兜底,如上,若路径/home和/about都未匹配上,则使用Redirect组件,发现其路径是/about,故匹配About组件。

例四:嵌套路由

App:

<Switch>
	<Route path="/home" component={Home}/>
	<Route path="/about" component={About}/>
	<Redirect to="/about" />
</Switch>

Home:

<MyNavLink to="/home/news">News</MyNavLink>
<MyNavLink to="/home/message">Message</MyNavLink>
							
<Switch>
	<Route path="/home/news"    component={News}/>
	<Route path="/home/message" component={Message}/>
	<Redirect to="/home/news"/>
</Switch>

3.路由传参

路由组件的props

//每个路由组件上都有history、location、match三个对象

//上面有go、goBack、goForword、push、replace等方法
history:{
    //或POP
    action:"PUSH",  
    //路由栈的长度,
    length:4    
    location:{....}
}
//来自hisroty上的location
location:{
    hash: ""
	key: "t3t15u"
	pathname: "/home/message/detail/"
    //查询字符串
	search: "?id=5&title=消息1"
    //通过state传递的参数
	state: undefined
}
match:{
    //是否是精准匹配
    isExact: true
    //params传递的参数
	params: {}
	path: "/home/message/detail"
	url: "/home/message/detail/"
}

例一:传递params参数

<Link to={`/home/message/detail/5/${title}`}>新闻标题</Link>

//声明接受params参数
<Route path="/home/message/detail/:id/:title" component={Detail}/>

路由组件:

// 接收params参数
const {id,title} = this.props.match.params

例二:传递state参数

实际上,route的to写成字符串是一种简写形式,完整形式应该为一个对象,对象有一个key为state

const routerObj={pathname:'/home/message/detail',state:{id:5,title:'参数'}
<Route to={routerObj}/>

路由组件:

// 接收state参数
const {id,title} = this.props.location.state || {}

例三:传递search参数

//查询字符串
<Link to={`/home/message/detail/?id=5&title=${title}`}>新闻标题</Link>

//正常注册路由
<Route path="/home/message/detail" component={Detail}/>

路由组件:

// 接收search参数
const {search} = this.props.location
const {id,title} = qs.parse(search.slice(1))

路由传参总结

除了params传递参数需要在Route声明接受外,其它的都正常注册,然后组件内部在props上取得参数。

Search查询字符串方法较麻烦,一般不用。

4.高级使用

例一:replace路由

<Link replace to="/home">Home</Link>

replace表示匹配的路由不是压栈,而是代替栈顶的路由。

例二:编程式路由导航

路由组件:

	replaceShow = (id,title)=>{
		//replace跳转+携带params参数
		//this.props.history.replace(`/home/message/detail/${id}/${title}`)

		//replace跳转+携带search参数
		// this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)

		//replace跳转+携带state参数
		this.props.history.replace(`/home/message/detail`,{id,title})
	}

	pushShow = (id,title)=>{
		//push跳转+携带state参数
		this.props.history.push(`/home/message/detail`,{id,title})
		
	}

	back = ()=>{
        //栈顶指针向下移动1位
		this.props.history.goBack()
	}

	forward = ()=>{
        //栈顶指针向上移动1位
		this.props.history.goForward()
	}

	go = ()=>{
		this.props.history.go(-2)
	}
    
    <button onClick={()=>this.pushShow(5,'test')}>跳转</button>

例三:withRouter的使用

一般组件是没有路由组件上面的hisroty等属性和方法的,所以引入了withRouter。

import { withRouter } from "react-router-dom";

class Header extends Component {
	render() {
        //可以看到history、location、match属性
        console.log(this.props)
		return (
			<div>
				Test
			</div>
		)
	}
}

//包裹一层
export default withRouter(Header)

五、组件通信

1.pubsub-js 消息订阅

pubsub-js是一个消息订阅库,可在任意框架中使用。

//下载
npm install pubsub-js --save
//组件中引入
import PubSub from 'pubsub-js' 

//订阅方:
//订阅消息,回调的第一个参数为消息名(delete)(饱受诟病)
this.id= PubSub.subscribe('delete', (title,data)=>{})
//组件销毁前要取消订阅
PubSub.unsubscribe(this.id)

//发布方:
//发布消息
PubSub.publish('delete', '我是参数')

2.redux

redux是一个专门用于做状态管理的JS库(不是react插件库),可在任意框架中使用,但一般只在react中使用。

工作流程:

image-20210723221302483

文件结构:

image-20210723221546973

constant中定义枚举类型

/* 
	该模块是用于定义action对象中type类型的常量值,目的只有一个:便于管理的同时防止程序员单词写错
*/
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
export const ADD_PERSON = 'add_person'

actions中一般导出一个action的创建函数

/* 
	该文件专门为Count组件生成action对象
*/
import {INCREMENT,DECREMENT} from '../constant'

//同步action,就是指action的值为Object类型的一般对象
export const increment = data => ({type:INCREMENT,data})
export const decrement = data => ({type:DECREMENT,data})

//异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
export const incrementAsync = (data,time) => {
	return (dispatch)=>{
		setTimeout(()=>{
			dispatch(increment(data))
		},time)
	}
}

reducers中创建出reducer

/* 
	1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
	2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
*/
import { INCREMENT, DECREMENT } from '../constant'

const initState = 0 //初始化状态
//导出reducer
export default function countReducer(preState = initState, action) {
	//从action对象中获取:type、data
	const { type, data } = action
	//根据type决定如何加工数据
	switch (type) {
		case INCREMENT: //如果是加
			return preState + data
		case DECREMENT: //若果是减
			return preState - data
		default:
			return preState
	}
}

srote一般汇总所有reducer

/* 
	该文件专门用于暴露一个store对象,整个应用只有一个store对象
*/
//引入createStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//引入redux-thunk,用于支持异步action
import thunk from 'redux-thunk'

//暴露store
export default createStore(countReducer,applyMiddleware(thunk))

ps:createStore第一个参数只接受一个reducer,所以要在reducers文件的index.js进行汇总,如下:

/* 
	该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
//引入为Person组件服务的reducer
import persons from './person'

//汇总所有的reducer变为一个总的reducer
export default  combineReducers({
	count,
	persons
})

使用

如在count组件中使用:

//引入store
import Store from '../../redux/store'

Store.getState('count')

3.react-redux

4.补充

reateStore,专门用于创建redux中最为核心的store对象
import {createStore,applyMiddleware} from ‘redux’
//引入为Count组件服务的reducer
import countReducer from ‘./count_reducer’
//引入redux-thunk,用于支持异步action
import thunk from ‘redux-thunk’

//暴露store
export default createStore(countReducer,applyMiddleware(thunk))


**ps:createStore第一个参数只接受一个reducer,所以要在reducers文件的index.js进行汇总,如下:**

```js
/* 
	该文件用于汇总所有的reducer为一个总的reducer
*/
//引入combineReducers,用于汇总多个reducer
import {combineReducers} from 'redux'
//引入为Count组件服务的reducer
import count from './count'
//引入为Person组件服务的reducer
import persons from './person'

//汇总所有的reducer变为一个总的reducer
export default  combineReducers({
	count,
	persons
})

使用

如在count组件中使用:

//引入store
import Store from '../../redux/store'

Store.getState('count')

3.react-redux

4.补充

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:20:57  更:2021-07-24 11:21:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 13:31:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码