React理论知识总结

模块化

commonjs

  • 如果在浏览器中使用commonjs,浏览器不认识commonjs语法,所以需要使用第三方包browserify,将commonjs转成浏览器认识的语法
  • 导出:module.exports / exports
  • 导入:require("./自定义包") require(“第三方包名”)

ES6

浏览器依然不认识es6模块化语法,需要使用babel将es6的语法转成commonjs,然后通过browserify转成浏览器认识的语法

  • 导出:
    分别导出: export 值
    统一导出: export {值,值}
    默认导出: export default 值 默认导出在一个模块中只能写一次

  • 导入

分别导出和统一导出都是

import {
     } from "路径/包"

默认导出

import 变量名自定义 from "路径/包"

webpack

  • 就是将前端代码(js,css,html…)打包成静态资源的打包工具

  • 五个核心概念:entry(入口),output(输出),loader(加载器),plugin(插件),mode(模式)
    entry:指定入口文件
    output:指定打包后的文件放在那里
    loader:webpack只能处理js和json,如果需要处理其他文件,需要使用loader
    plugin:如果loader不能完成某个功能,可以使用插件
    mode:指定环境 development(开发环境) production(生产环境)

  • webpack配置文件的名称:webpack.config.js(定义在项目的根目录)

  • webpack配置文件主要写两个
    开发环境:webpack.dev.js 需要配置devServer 帮助开发者自动编译刷新
    开发环境,配置了devserver,实际上启动之后,在内存中创建了dist文件夹

    生产环境:webpack.prod.js 不需要配置devServer
    生产环境,当我们将所有的代码写完,测试完毕,直接打包项目,得到硬盘上的一个dist文件夹,直接将这个文件夹交给运行上线

  • 当我们配置了两个配置文件,启动的时候,就不能直接使用webpack
    需要在package.json中配置scripts

{
     
   "scripts": {
     
        "start": "webpack-dev-server --config ./config/webpack.dev.js",
        "build": "webpack --config ./config/webpack.prod.js"
    }
}

如果配置了package.json 开发环境启动项目,以及生产环境打包dist文件夹都不需要直接输出webpack/webpackdevserver 而是使用npm

npm run start —简写— npm start
npm run bulid

React环境/组件

react是一个用于构建用户界面的js库

react依赖哪些包?

react 提供一些核心的api
react-dom 提供了一些dom的api
babel 将jsx转成浏览器认识的代码

react是如何创建元素?

React.createElement()通过这个函数,创建了react元素(虚拟dom),然后react底层会根据这个虚拟dom创建真实dom,然后渲染到页面上

ReactDOM.render()这个函数真正将虚拟DOM渲染到页面上

jsx

javascript xml 是js中的一个语法糖
可以让我们在js中直接写标签

脚手架工具

create-react-app
方式一:

npm i create-react-app -g
create-react-app  项目名称

方式二:

npx create-react-app 项目名称

注意:
public文件夹下面至少要有一个index.html
src文件夹下面至少要有一个index.js

import React from "react"
import ReactDOM from "react-dom"
ReactDOM.render()

组件

其实就是将结构和数据封装封装到一个js文件中 实现复用

  • 函数组件
function Module() {
     return div}
  • 类组件
    定义
class Module extends React.Component{
     
	render(){
     
		return div
	}
}

定义状态

constructor(){
     
	super()
	this.state = {
     
		count : 0;
	}
}

获取状态

this.state.count

修改状态

this.setState({
     count:})

使用组件

<Module/>

注意点:
首字母要大写
返回的结构必须有一个根标签
当成标签去使用

props/表单处理

this指向问题

  • 问题原因:
    事件处理函数,底层执行的时候是普通调用,这时按道理this应该指向windows
    由于代码被babel编译过,成为了严格模式,所以指向undefined

  • 解决办法
    1.箭头函数

箭头函数  () =>{
     }

2.bind

// 给当前组件实例增加了一个handle方法,这个方法的this被固定指向了当前组件实例
constructor(){
     
	super()
	this.handlexxx = this.handle.bild(this)
}

3.ES7新的语法(类的实例方法)

handlexxx = () => {
     }

props

作用:接收组件外部数据
如何传递:

如何接收?
类组件

 this.props.xxx

函数组件

function Header(props){
     
	return <div>{
     props.xxx}</div>
}

props效验
使用组件时,传入的数据不对,可以报出更清晰的错误

import PropTypes from "prop-types"

组件.propTypes = {
     
	属性.PropTypes.string.isRequired
}

默认props

组件.defaultProps = {
     }

props的特点
props是只读属性,不要给props赋值

表单处理

受控组件
表单项的值,被组件的状态所控制,想要获取表单项的值,直接从状态中获取
文本框/下拉框/文本域/单选框 直接通过value属性控制,复选框,用checked属性控制
都要配合onchange事件,在这个事件里面,获取用户输入添加到状态中

非受控组件
直接操作dom

使用Reac.createRef()  得到的ref对象和标签绑定
<input ref={
     ref对象}>
获取真实dom  ref对象.current指向真实dom

高阶函数(函数柯里化)

// 原始写法
function fn(name){
     
	return (e)=>{
     
	}
}

// 简写
let fn = name => e =>{
     }

todos案例

如果多个组件,都使用同一份数据,这个数据应该放到他们的父组件中

传递数据

组件之间传递数据

  1. props
    父=>子 用props传
    子=>父 父组件中定义函数,将函数传递给子组件,子组件调用函数,将数据当做实参传递给父组件

  2. context

注意:保证是同一个context对象
一般只用来传递一些简单的数据

自上而下跨级传递数据
创建context对象 React.createContext(“默认值”)
在传递数据的组件中写Provider组件 value属性的值就是要传递的数据

<Provider value={
     要传递的值}> 
  <div className="App"> 
    <Child1 /> 
  </div> 
</Provider>

在使用数据的组件中写consumer组件

<Consumer>{
     data => <span>data参数表示接收到的数据 -- {
     data}</span>} </Consumer> 

第二种使用方式,给组件添加静态属性contextType

export default class Demo extends Component {
     
    // 给要使用的Context的Demo类,添加静态contextType属性, 并赋值为context对象
    // 那么在Demo的实例对象上context属性中就可以获取到需要的值
  static contextType = MyContext
  render() {
     
    // return {data => 

{data}

}
return <div>{ this.context}</div> } }
  1. pubsubjs
    是一个js库,在react/vue中都可以使用
// 下载包
npm i pubsub-js

// 导入
import PubSub from "pubsub-js"

//api
PubSub.publish("话题",数据)
PubSub.subscribe("话题",("话题",数据)=>{
     })   组件挂载成功的时候写
PubSub.unsubscribe(token/话题)取消订阅    组件卸载的时候取消

生命周期

创建阶段
constructor 定义状态
render 返回结构
componentDidMount 订阅pubsub发送请求/操作dom

更新阶段
render 注意:不要在这里调用setStat,否则递归死循环
componentDidUpdate 注意:如果一定要调用setState:需要给if给个出口

卸载阶段
componentWillUnMount 取消订阅/取消定时器/取消一些dom原生的事件

fragment

<React.Fragment></React.Fragment>

<></>  包裹结构,但是不会渲染根标签

性能优化

1.减轻state,跟视图无关的数据,不要卸载state里面,可以直接加到this上面
2.shouldComponentUpdate 返回true,组件才更新,返回false,组件不更新

shouldComponentUpdate(nextProps,nextState)

// 判断state和props是否变化,有一个变化了才更新,否则不更新

3.PrueComponent(纯组件)
底层帮我们写了shouldComponentUpdate,但是是浅层对比
注意:修改状态的时候,不要直接在原来的数据的基础上修改,应该根据原来的数据,得到一个新的数据,修改新的数据

高阶组件/renderProps/hooks

高阶组件

作用:将多个组件中公用的状态和逻辑封装起来,实现复用
写法:

// 1.定义一个函数
function withXXX(WrappedComponent){
     
	return class extends Component{
     
		...定义公共状态和逻辑
	}

	render(){
     
		return (
			<wrappedComponent {
     ...this.state}{
     this.props}/>
		)
	}
}

使用

const 新的组件 = withXXX(需要使用状态和逻辑的组件)
然后渲染的是新的组件

问题
1.传递props的问题:在封装的高阶组件里面直接将props传递下去
2.在react-dev-tool中,展示高阶组件名字的时候不清晰 给高阶组件加一个静态属性static displayName

renderProps

作用:将多个组件中公共的状态和逻辑封装起来,实现复用
写法:

// 1.定义一个组件
class XXX extends Component{
     
	...定义状态和逻辑
	render(){
     
		// return this.props.render(数据)
		return this.props.children(数据)
	}
}

// 2.使用
<Position render={
     data => 需要使用状态和逻辑的组件}><Position>
<Position>{
     data => 需要使用状态和逻辑的组件}</Position>

Hook

hooks的作用:
在函数组件中,可以使用类组件的一些功能(比如:可以定义状态或定义生命周期的钩子函数)

常用的hooks
useState(在函数中定义状态)

// 导入
import {
     useState} from "react"

// 使用
const [状态的属性,操作状态的方法] = useState(初始值)  可以使用多次

useEffect(在函数组件中模拟生命周期钩子函数)

// 导入
import {
     useEffect} from "react"

使用:
useEffect(()=>{
     },[])

第一个回调函数,默认模拟componentDidMount和componentDidUpdate
如果第二个参数传入的是空数组,第一个回调函数只模拟componentDidMount
如果在第二个参数的数组中,监听的数据,那么当监听的数据发生变化的时候,第一个参数的回调函数也可以模拟componentDidUpdate

useEffect(()=>{
     
	return ()=>{
     
	}
})
第一个参数的回调函数中,可以返回一个回调函数,这个回调函数模拟的是componentWillUnmount

hooks使用的规则
1.不管是react提供的hooks,还是第三方的hooks,还是自己定义的hooks,都遵守下面的规则
2.规则
hooks只能在函数组件和自定义hooks中使用
在函数组件和自定义hooks中使用其他hooks的时候要求写在顶级作用域,千万不要写在if/循环/嵌套的普通函数中
3.自定义hooks
看起来就像是一个普通的函数 自定义hooks的名字都应该是useXXX

react-router

redux

redux是什么?

是一个状态管理的js库
集中管理数据

redux中三个重要的核心概念

  • action
    表示需求,action至少有一个type属性,描述需求类型
实现方式 : {
     type:"INCREMENT"}
  • reducer
    表示具体执行需求的角色
// 实现方式:函数
function fn(state={
     xxx:"默认值",action}){
     
	switch(action.type){
     
		case 需求:
			return 最新数据
		default:
		 	return state
	}
}

注意:reducer在创建store的时候会被调用一次,这次调用会走default,用来初始化redux中的数据

每一次调用dispatch的时候,reducer也会被调用,redux会自动将最新的数据传递给state参数,将需求传递给action参数

  • store
    创建store
const store对象 = createStore(reducer函数)

const store对象 = createStore(reducer函数,applyMiddleware(中间件,中间件.中间件))   如果要使用中间件

写reducer的时候注意点

一般分成四个文件去写
1.actions.js 在这里定义同步的action和异步的action
2.constants.js 定义一些常量(需求类型)
3.reducer.js 定义reducer函数
4.store.js 创建store

在react中使用redux

  • 需要使用react-redux包
  • 使用react-redux这个包的时候,会有一个顶层的思想,要有容器组件和展示组件

展示组件,其实就是react组件
通过props,去获取redux的数据和操作redux数据的方法

容器组件,就是使用connect函数得到的组件
职责::将redux中的数据和操作redux数据的方法,传递给展示组件

react-redux的具体使用

  • 在App根组件中
// 导入Provider
import {
     Provider} from "react-redux"

<Provider store={
     store}>
	<WithList></WithList>
<Provider>

// 包裹其它组件和结构,包裹的同时,传递store对象
  • 在哪个组件中需要用到redux的数据,就针对这个组件,写一个容器组件,然后再在这个容器组件中传递数据和操作数据的方法
// 导入connect组件
import {
     connect} from "react-redux"
// 导入展示组件
import List from "./page/List"
// 导入操作redux数据的方法(异步action)
import {
     getUserAsync} from "./redux/actions"

const WithList = connect(state => {
     {
     users:state.users}},{
     getUsersAsync})(List)

export default WithList
  • const 容器组件 = connect(传给展示组件的数据,传给展示组件操作redux数据的方法)(展示组件)

  • 对于connect函数的描述

//connect函数,内部结构
function connect(){
     
	return function(){
     
		return class extends Component{
     
		}
	}
}
  • connect第一次调用传参的方式
    第一个参数:
    state => {属性名:state.属性名}
    第一次connect函数执行的时候,这个函数会被调用,state接收的就是redux中最新的数据,return的对象就是添加到展示组件props身上的数据

后面如果redux中数据发生了变化,react-redux还会继续调用这个函数,将最新的数据传递给真实的组件,所以在展示组件中永远可以自动获取到最新的数据

第二个参数:
传入一个对象{actionCreator,actionCreator}

注意:在展示组件中,可以获取到相同名称的函数,但是在展示组件中拿到的函数,不是真正的actionCreator,只是名字相同而已
connect函数将传入的actionCreaor进行了一次封装

比如actionCreator的名字叫做inc connect会根据合格inc新建一个函数

function inc(){
     //这个inc是传递给展示组件的函数
	diapatch(inc())  //这个inc是actionCreator
}

redux-thunk的使用

首先 redux中默认不支持异步操作
但是在实际开发中,经常要发送请求获取数据
需要利用redux-thunk去实现异步操作

使用:

// 在action.js中定义一个异步action

function 异步antion名字(){
     
	return dispatch =>{
     
		//发送异步请求

		//异步请求成功的时候
		dispatch(同步action)
	}
}

你可能感兴趣的:(React)