React16新手教程记录

文章目录

  • 前言
  • 一些前端面试题
  • [1. 搭建项目](#1. 搭建项目)
    • [1. 1 cdn](#1. 1 cdn)
    • [1. 2 脚手架](#1. 2 脚手架)
  • [2. 基础用法](#2. 基础用法)
    • [2.1 表达式和js语句区别:](#2.1 表达式和js语句区别:)
    • [2.2 jsx](#2.2 jsx)
    • [2.3 循环map](#2.3 循环map)
    • [2.4 函数式组件](#2.4 函数式组件)
    • [2.5 类式组件](#2.5 类式组件)
    • [2.6 类组件点击事件](#2.6 类组件点击事件)
      • [2.6.1 事件回调函数this指向](#2.6.1 事件回调函数this指向)
      • [2.6.2 this解决方案](#2.6.2 this解决方案)
        • [2.6.2.1 通过bind](#2.6.2.1 通过bind)
        • [2.6.2.2 箭头函数(推荐)](#2.6.2.2 箭头函数(推荐))
  • 3.state
  • [4. props](#4. props)
    • [4.1 props接受,校验](#4.1 props接受,校验)
    • [4.2 props与state的区别](#4.2 props与state的区别)
  • [5. refs](#5. refs)
    • [5.1 字符串类型的ref(不建议使用字符串类型,性能影响)](#5.1 字符串类型的ref(不建议使用字符串类型,性能影响))
    • [5.2 回调方法赋值](#5.2 回调方法赋值)
    • [5.3 createRef方法(只能放一个,class组件使用)](#5.3 createRef方法(只能放一个,class组件使用))
    • [5.4 useRef 方法(函数组件使用)](#5.4 useRef 方法(函数组件使用))
  • [6. 生命周期](#6. 生命周期)
    • [6.1 react16版本的生命周期](#6.1 react16版本的生命周期)
    • [6.2 react17版本的生命周期](#6.2 react17版本的生命周期)
  • [7. cdn源码文件](#7. cdn源码文件)
  • [8. 脚手架相关](#8. 脚手架相关)
    • [8.1 样式隔离](#8.1 样式隔离)
    • [8.2 组件通信](#8.2 组件通信)
      • [8.2.1 父子组件通信(props)](#8.2.1 父子组件通信(props))
      • [8.2.2 兄弟组件通信](#8.2.2 兄弟组件通信)
      • [8.2.3 祖孙组件通信](#8.2.3 祖孙组件通信)
    • [8.3 本地代理](#8.3 本地代理)
      • [8.3.1 package.json](#8.3.1 package.json)
      • [8.3.2 http-proxy-middleware](#8.3.2 http-proxy-middleware)
  • [9. react-router(通过拦截浏览器路径变化)](#9. react-router(通过拦截浏览器路径变化))
    • [9.1 路由的概念](#9.1 路由的概念)
    • [9.2 路由的原理](#9.2 路由的原理)
    • [9.3 react-router-dom](#9.3 react-router-dom)
      • [9.3.1 内置组件](#9.3.1 内置组件)
        • [9.3.1.1 Link,Route ,BrowserRouter](#9.3.1.1 Link,Route ,BrowserRouter)
        • [9.3.1.2 NavLink,Redirect,IndexRoute,Switch](#9.3.1.2 NavLink,Redirect,IndexRoute,Switch)
        • [9.3.1.3 withRouter](#9.3.1.3 withRouter)
      • [9.3.2 路由跳转参数](#9.3.2 路由跳转参数)
      • [9.3.3 编程式导航](#9.3.3 编程式导航)
  • 10.redux
    • [10.1 三个概念](#10.1 三个概念)
      • [10.1.1 store, action](#10.1.1 store, action)
      • [10.1.2 reducers](#10.1.2 reducers)
      • [10.1.3 state变化后触发render](#10.1.3 state变化后触发render)
    • [10.2 核心Api](#10.2 核心Api)
  • 11.react-redux
  • 12.hooks(解决函数式组件的state,ref)
    • [12.1 useState](#12.1 useState)
    • [12.2 useEffect(模拟生命周期)](#12.2 useEffect(模拟生命周期))
    • [12.3 useRef](#12.3 useRef)
  • 13.扩展
    • [13.1 组件懒加载](#13.1 组件懒加载)
    • [13.2 Fragment](#13.2 Fragment)
    • [13.3 Context(祖孙组件通信)](#13.3 Context(祖孙组件通信))
    • [13.4 错误边界(Error Boundaries)](#13.4 错误边界(Error Boundaries))
    • [13.4 PureComponent](#13.4 PureComponent)

前言

新手React上路:从建立项目开始


一些前端面试题

其他博主的面试记录

1. 搭建项目

1. 1 cdn

bash 复制代码
	// 可以访问react
    <script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
    // 可以访问ReactDOM
    <script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
    // babel插件
    <script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>

1. 2 脚手架

命令行搭建项目:npm 5.2.0 以上版本,会自动安装npx。npx说白了就是会先查看安装包在不在。若不存在,npx将安装其最新版本,然后执行它;

JavaScript 复制代码
# npm:构建一个my-app的项目
npm install -g create-react-app
create-react-app my-app

# npx:构建一个my-app的项目
npx create-react-app my-app

#进入项目进行编译
cd my-app
npm start

2. 基础用法

2.1 表达式和js语句区别:

js表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方。

bash 复制代码
a
a+b
map
methos
function(){}

js语句:js语法相关的代码

bash 复制代码
if
for
switch

2.2 jsx

使用{},内部放js表达式

bash 复制代码
        const user = {
            name: '罗测试',
            imageSize: 100,
            imageUrl: 'https://react.dev/_next/image?url=%2Fimages%2Fuwu.png&w=64&q=75'
        }
        const element1 =
            <div>
                <h1>普通的jsx:</h1>
                {/*class绑定使用className,属性,内联样式可以通过大括号{ }进行动态绑定*/}
                <img className="avatar" src={user.imageUrl} style={{
                    width: user.imageSize,
                    height: user.imageSize
                }} />
                {/*界面内容使用{ }动态绑定*/}
                <h1>
                    {user.name}
                </h1>
            </div>

        ReactDOM.render(element1, document.getElementById('app'))

2.3 循环map

bash 复制代码
const products = [
  { title: 'Cabbage', id: 1 },
  { title: 'Garlic', id: 2 },
  { title: 'Apple', id: 3 },
];
const listItems = products.map(product =>
  <li key={product.id}>
    {product.title}
  </li>
);

return (
  <ul>{listItems}</ul>
);

2.4 函数式组件

函数式组件: 首字母大写,小写会被视为html标签
可以通过参数操作props,但是ref和state不能使用修改

bash 复制代码
		function Head() {
            // this为undefined,因为babel翻译转换为严格模式,严格模式的this为undefined
            console.log('我是函数内部的this'+this)
            return <div>我是头部</div>
        }
        function Dom1() {
            return (
                <div>
                    <Head/>
                </div>
            )
        }
        /* 
            1.react解析组件标签,找到相关租价
            2.发现组件是用函数定义的,随后调用该函数。将返回的dom转换为真实dom
        */
        ReactDOM.render(<Dom1/>, document.getElementById('app'))

注意:函数时编程内部的this是undefined

2.5 类式组件

  • es6复习:
    1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作才写
    2.如果a类集成了b类,且a写了构造器,那需要在构造器最上面添加super
    3.类中定义的方法,都是放在类的原型对象上,供实例使用
    4.类中的方法,使用实例调用指向的是实例,否则指向调用的对象
  • 类组件代码(必须要继承React.Component):
    1.constructor调用一次
    2.render调用1+n次,n是状态更新的次数
bash 复制代码
		// 类式组件: 必须要继承React.Component
        class Footer extends React.Component{
            // render 是放在 Footer组件 的实例对象上的,
            render(h) {
                console.log('我是类式组件render的this:',this)
                return <div className="text-center">我是底部</div>
            }
        }
        function Dom1() {
            return (
                <div>
                    <Footer/>
                </div>
            )
        }
        /* 
            1.react解析组件标签,找到相关租价
            2.1发现组件是用函数定义的,随后调用该函数。将返回的dom转换为真实dom
            2.2发现组件是用类定义的,随后new出来该类的实例。并通过实例调用原型上的render方法。将返回的dom转换为真实dom
        */
        ReactDOM.render(<Dom1/>, document.getElementById('app'))

2.6 类组件点击事件

2.6.1 事件回调函数this指向

bash 复制代码
class Container extends React.Component {
    constructor(props) {
        super(props)
    }
    changeHot() {
        console.log('我是类中方法的this值是undefined', this)
    }
    render(h) {
        return (
            <div>
                {/*state使用
                    1.通过this指向原型对象才能找到changeHot方法。
                    2.changeHot执行是作为onClick回调执行,不是通过实例执行。
                        所以changeHot内部this是直接调用所以指向window,但是因为babel,所以是undefined
                    3.
                */}
                <h1 onClick={this.changeHot}>1.今天天气好</h1>
            </div>
        )
    }
}

2.6.2 this解决方案

2.6.2.1 通过bind
bash 复制代码
class Container extends React.Component {
    constructor(props) {
        super(props)
        // 给实例对象添加了一个changeHot方法 = 修改changeHot函数内部的this,指向Container实例
        // bind返回构造函数,需要调用。call,apply是直接执行
        this.changeWeather = this.changeHot.bind(this);
    }
    changeHot() {
        console.log('我是类中方法的this值是实例', this)
    }
    render(h) {
        return (
            <div>
            	{/*通过bind修改changeHot内部this指向*/}
                <h1 onClick={this.changeWeather}>2.今天天气好</h1>
                <h1 onClick={this.changeHot.bind(this)}>3.今天天气好</h1>
            </div>
        )
    }
}
2.6.2.2 箭头函数(推荐)
bash 复制代码
class Container extends React.Component {
    //可以直接写赋值语句,是给实例上添加属性
    exTip = "今天天气好"
    // 使用箭头函数,定义时上层作用域中的this
    changeHotEasy = () => {
        this.setState({ 'isHot': !this.state.isHot })
    }
    changeHot() {
        console.log('我是类中方法的this值是实例', this)
    }
    constructor(props) {
	    super(props)
	    this.state = {
	    	isHot: true
	    }
    }
    render(h) {
    	return (
	    	<h1 onClick={this.changeHotEasy}>4.{exTip}{isHot ? '热' : '冷'}</h1>
	    	<h1 onClick={() => this.changeHot()}>5.{this.exTip}{isHot ? '热' : '冷'}</h1>
    	)
    }
}

3.state

状态不能直接更改,必须通过setState修改

bash 复制代码
class Container extends React.Component {
	//可以直接写赋值语句,是给实例上添加属性
    exTip = "今天天气好"
    state = {
	    isHot: true,
	    tips: '我很牛'
    }
    constructor(props) {
        super(props)
        // this.state = {
        //     isHot: true,
        //     tips: '我很牛'
        // }
    }
    changeHot() {
        // 状态不能直接更改,必须通过setState修改
        // this.state.isHot = false
        // setState是合并,不是赋值,修改isHot不影响tips
        this.setState({ 'isHot': !this.state.isHot })
        // 函数方式语法
        this.setState((state, props)=>{
        	return { conut: state.conut + 1 }
        })
    }
    render(h) {
        const { isHot, tips } = this.state
        return (
            <div>
            	<h1 onClick={() => this.changeHot()}>5.{this.exTip}{isHot ? '热' : '冷'}</h1>
            </div>
        )
    }
}	 		

4. props

4.1 props接受,校验

props是单项数据流,不能修改

bash 复制代码
// html引入限制库
<!-- 引入prop-type,用于组件标签props属性进行限制 -->
<script src="https://cdn.staticfile.net/prop-types/15.6.1/prop-types.js"></script>

//js添加
const products = [
    { title: 'Cabbage', id: 1 },
    { title: 'Garlic', id: 2 },
    { title: 'Apple', id: 3 },
]
class CardList extends React.Component {
    static propTypes = {
        // array,number,string,func,boolean...
        listItems: PropTypes.array.isRequired
    }
    static defaultProps = {
        listItems: [],
        name: '默认,就算没传,也是可以查到的'
    }
    render(h) {
        return (
            <div>
                {
                    this.props.listItems.map(item => {
                        return <div key={item.id}>{item.id}:{item.title}</div>
                    })
                }
            </div>
        )
    }
}
// 对标签属性进行数据类型,必填限制
// CardList.propTypes = {
//     // array,number,string,func,boolean...
//     listItems: PropTypes.array.isRequired
// }
// // 添加标签属性默认值
// CardList.defaultProps = {
//     listItems: []
// }
function Dom1() {
    return (
        <div>
            <CardList listItems={products} />
        </div>
    )
}
ReactDOM.render(<Dom1 />, document.getElementById('app'))

4.2 props与state的区别

javascript 复制代码
props:指组件间传递的数据,由父对子进行传递。React的数据流是自上而下的,所以组件内部的props是只读的不可修改!
state:组件内部的数据,不能够直接修改,使用setState来改变数据。

5. refs

元素对应ref返回元素本身,组件返回组件实例

5.1 字符串类型的ref(不建议使用字符串类型,性能影响)

通过ref属性,绑定ref值。通过refs获取。

bash 复制代码
class Dom1 extends React.Component {
    getRefs = () => {
        console.log(this.refs);
    }
    render() {
        return (
            <div>
            	<Container ref="container" />
                <h1 ref="h1" onClick={() => this.getRefs()} > 点我市市</h1>
            </div>
        )
    }
}

5.2 回调方法赋值

在ref属性绑定值的时候通过回调函数赋值。(会调用多次)

bash 复制代码
class ContainerRef extends React.Component {
    // 回调赋值方式获取
    getH2 = () => {
        console.log(this.h2Ref);
    }
    render(h) {
        return (
            <div>
                <h2 ref={(event) => this.h2Ref = event} onClick={() => this.getH2()}> 点我市市2</h2>
            </div>
        )
    }
}

解决方案(调用多次):通过ref回调函数方式

bash 复制代码
class ContainerRef extends React.Component {
    getH2 = () => {
        console.log(this.h2Ref);
    }
    // 通过ref回调函数方式
    setRefH2 = (event) => {
        this.h2Ref = event
    }
    render(h) {
        return (
            <div>
                <h2 ref={this.setRefH2} onClick={() => this.getH22()}> 点我市市2.2</h2>
            </div>
        )
    }
}

5.3 createRef方法(只能放一个,class组件使用)

每个容器需要新建一个

bash 复制代码
		class ContainerRef extends React.Component {
            getRefs = () => {
                console.log(this.myRef1.current);
                console.log(this.myRef2.current);
            }
            // ======createRef方式获取=======
            myRef1 = React.createRef()
            myRef2 = React.createRef()
            render(h) {
                return (
                    <div>
                        <h1 ref={this.myRef1} onClick={() => this.getRefs()} > 点我市市3</h1>
                        <h1 ref={this.myRef2} onClick={() => this.getRefs()} > 点我市市4</h1>
                    </div>
                )
            }
        }

5.4 useRef 方法(函数组件使用)

bash 复制代码
import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        聚焦这个输入框
      </button>
    </>
  );
}

6. 生命周期

6.1 react16版本的生命周期

// 挂载的流程

  1. constructor》
  2. componentWillMount(挂载前)》
  3. render》
  4. componentDidMount(挂载后)

// setState之后(手动更新)

  1. shouldComponentUpdate(默认返回真,控制是否更新视图)》
  2. componentWillUpdate(更新前)》
  3. render》
  4. componentDidUpdate(更新后)

// 强制更新(实例方法:forceUpdate)

  1. forceUpdate》
  2. componentWillUpdate...

// 父组件更新子组件的props,子组件会触发

  1. componentWillReceiveProps》
  2. shouldComponentUpdate...

// 卸载的流程

  1. componentWillUnmount(卸载前)》

// 手动卸载(卸载,ReactDOM方法)

unmountComponentUnmountAtNode

bash 复制代码
class ComponentsLive extends React.Component {
    state = {
        test: 0
    }
    constructor(props) {
        console.log('constructor');
        super(props)
    }
    // 挂载前
    componentWillMount() {
        console.log('componentWillMont');
    }
    // 挂载后
    componentDidMount() {
        console.log('componentDidMont');
    }
    changeTest = () => {
        console.log('调用setState了');
        this.setState({ test: this.state.test++ })
    }
    // 更新前
    componentWillUpdate() {
        console.log('componentWillUpdate');
    }
    // 更新后
    componentDidUpdate() {
        console.log('componentDidUpdate');
    }
    // 卸载前
    componentWillUnmount() {
        console.log('componentWillUpdate');
    }
    render() {
        console.log('render');
        return (
            <div onClick={this.changeTest}>生命周期</div>
        )
    }
}

6.2 react17版本的生命周期

调整3个:三个will生命周期前面添加UNSAFE_

componentWillMount》UNSAFE_componentWillMount

componentWillReceiveProps》UNSAFE_componentWillReceiveProps

componentWillUpdate》UNSAFE_componentWillUpdate

新增2个:

getDeriveStateFromProps():替换为componentWillMount的位置

getSnapshotBeforeUpdate():替换为componentWillUpdate的位置

7. cdn源码文件

github地址链接

8. 脚手架相关

8.1 样式隔离

样式的内部用父级类名或者id标识做隔离

或者将css文件名前缀添加module,使用import {名称} form 'css地址'。然后类名使用{名称.属性名}写进className

8.2 组件通信

8.2.1 父子组件通信(props)

父传子:子通过props获取

bash 复制代码
//父组件
import React from "react"
import ChildComponent from "../childComponent"
class ParentComponent extends React.Component {
    state = {
        name: "parent",
        allList: [{ id: 0, name: "第一名" }, { id: 1, name: "第二名" }, { id: 2, name: "第三名" }]
    }
    //子传父:使用点击事件
    changeName(data) {
        this.setState({
            name: data //把父组件中的parentText替换为子组件传递的值
        });
    }
    //父传子:使用属性进行传参
    render() {
        const allList = this.state.allList;
        return (
            <div>
                <h1>{this.state.name}</h1>
                <ChildComponent allList={allList} changeName={(data) => this.changeName(data)} />
            </div>
        )
    }
}
export default ParentComponent;

子传父:子通过调用props的方法传递(父组件中定义好的)

bash 复制代码
// 子组件
import React from "react"
class ChildComponent extends React.Component {
    clickFun(text) {
        this.props.changeName(text)//把值传递给了props的事件当中
    }
    //使用属性进行传参
    render() {
        return (
            <div>
                <h1 onClick={() => { this.clickFun('变成子组件的数据') }}>点击改变父组件</h1>
                {/* 子组件通过props接受参数 */}
                {
                    this.props.allList.map((item) => {
                        return (<div key={item.id} >{item.name}</div>)
                    })
                }
            </div>
        )
    }
}
export default ChildComponent;

8.2.2 兄弟组件通信

  1. 通过props触发父组件,父组件在触发兄弟组件
  2. redux
  3. 消息订阅-发布(pubsub.js)
    pubsub.js的github地址

8.2.3 祖孙组件通信

  1. redux
  2. context生产者消费者模式
  3. 消息订阅-发布(pubsub.js)

8.3 本地代理

8.3.1 package.json

8.3.2 http-proxy-middleware

在src目录下创建一个setupProxy.js文件,必须是这个名称

bash 复制代码
const proxy = require('http-proxy-middleware')
module.exports = function (app) {
    app.use(
        proxy('/api', {
            target: 'https://api.zhiwucloud.com',
            changeOrigin: true,
            pathRewrite: {
                '^api': ''
            }
        })
    )
}

9. react-router(通过拦截浏览器路径变化)

9.1 路由的概念

1.什么是路由:

  • 一个路由就是一个映射关系
  • key为路径,value可能是function或者component

2.路由的分类:

  • 后端路由(是function,如接口)
  • 前端路由(component)

9.2 路由的原理

hash和history区别:地址栏上有#

bash 复制代码
// History用一个第三方插件history.js,封装的BOM的history
let history = History.creatBrowerHistory() // 使用的H5推出的history身上的API,可能旧浏览器不兼容
let history = History.creatHashHistory() // hash值锚点方式

封装的BOM的history,拦截history变化

bash 复制代码
// html代码
<a href="https://editor.csdn.net" onclick="return push('/test')></a>

// js代码
function push(path){
	// 界面栈添加一条路径记录
	history.push(path)
	// 不让浏览器进行界面跳转
	return false
}
// 界面栈替换当前
function replace(path){
	history.replace(path)
}
// 界面栈返回上一页
function back(){
	history.goBack()
}
// 界面栈前进一页
function forward(){
	history.forward()
}
history.listen(location)=>{
	console.log('路由发生变化啦,我监测到了')
}

9.3 react-router-dom

安装: npm install --save react-router-dom

9.3.1 内置组件

9.3.1.1 Link,Route ,BrowserRouter
  • BrowserRouter:Route,Link必须放在这个标签内部
  • Link:路由跳转,参数to是要展示的组件。replace属性接受布尔值,定义跳转是新增还是替换当前路径
  • Route:组件的内容展示,path与Link的to对应。exact属性:精准匹配(默认模糊匹配)
bash 复制代码
import './App.css'
import Home from './pages/home'
import About from './pages/about'
import { Link, BrowserRouter, Route } from 'react-router-dom'

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        跳转切换:
        <Link to="/about">跳转到about</Link>
        <Link to="/home">跳转到home</Link>
        {/* 内容区域 */}
        <div>
          <Route exact path="/about">
            <About />
          </Route>
          <Route exact path="/home">
            <Home />
          </Route>
        </div>
      </BrowserRouter>
    </div>
  );
}
export default App;
  • NavLink:可以实现链接的高亮,通过activeClassName设置高亮样式名称
bash 复制代码
import { NavLink, Redirect, IndexRoute, Switch} from 'react-router-dom'
<NavLink activeClassName="active" to="/home">跳转到home</NavLink>
  • Redirect:重定向到其他 route 而不改变旧的 URL。
  • IndexRoute:默认路由
  • Switch(单一匹配):匹配到一个路由后不在匹配。
    下面代码如果不用switch,则dataTable和alarmManagement都会展示,加上switch则只展示dataTable
bash 复制代码
<Switch>
	<IndexRoute component={Home}/>
    <Redirect from="/ddd" to="/alarmManagement" exact/>
    <Route exact path="/dataTable" component={dataTable}/>
    <Route exact path="/dataTable" component={alarmManagement}/>
    <Route exact path="/dashboard" component={dashboard}/>
    <Route exact path="/*" component={notFound}/>
</Switch>
9.3.1.3 withRouter

withRouter: 让一般组件能使用路由组件的api

bash 复制代码
import { withRouter} from 'react-router-dom'
import React from "react"
class Head extends React.Component {
	routePush(){
		this.props.history.goBack()
	}
    render() {
        return (
            <div onClick={()=>this.routePush}>
                我是Head
            </div>
        )
    }
}
export default withRouter(Head)

9.3.2 路由跳转参数

1.params参数
bash 复制代码
// 跳转的时候添加参数
<Link to="/pw/pbzb/666"></Link>

// 注册路由的地方接受
<Route path="/pw/pbzb/:id" component={PwPbzb}></Route>

//PwPbzb组件内部接受
console.log(this.props.match.params)
2.search参数
bash 复制代码
// 跳转的时候添加参数,urlencode
<Link to="/pw/pbzb?name=百度&articleId=108198330"></Link>

//PwPbzb组件内部接受
import * as queryString from 'querystring'
const { name, articleId } = queryString.parse(this.props.location.search.slice(1))
3.state参数(和状态管理state无关)
bash 复制代码
// 跳转的时候添加参数
<Link to={{
  pathname: '/pw/pbzb',
  state: {
    fromDashboard: true,
  	articleId: '108198330'
  }
}} />

//PwPbzb组件内部接受
const { fromDashboard, articleId} = this.props.location.state || {}
4.三种方式区别

params,search参数地址栏会展示

state不会展示在地址栏:history模式下他是存储在history的。所以当浏览器缓存清空后,参数会丢失。hash模式下界面刷新会丢失

9.3.3 编程式导航

bash 复制代码
// 跳转方法
this.props.history.push('/pw/pbzb', {
	fromDashboard: true,
	articleId: '108198330'
 })
this.props.history.replace(path, state)
// history前进后退相关操作
this.props.history.go(n)
this.props.history.goBack()
this.props.history.forword()

10.redux

10.1 三个概念

10.1.1 store, action

组件获取state:store.getState()

触发action:store.dispatch(type, data)

bash 复制代码
import React from "react"
import store from "../../redux/store"

class Home extends React.Component {
    addCount() {
        store.dispatch('increment', 1)
    }
    render() {
        return (
            <div>
                获取store数据:{store.getState()}
                <button onClick={() => this.addCount()}>加1</button>
            </div>
        )
    }
}
export default Home;

10.1.2 reducers

store.js

bash 复制代码
import { createStore } from 'redux'
import contReducer from './contReducer'
// 构建一个store并暴露,参数是reducer函数
export default createStore(contReducer)

contReducer.js

bash 复制代码
// 创建一个为count组件服务的reducer,本质就是一个函数
// 第一次调用是store自动触发的,preState是undefined
const initState = 0
export default function contReducer(preState = initState, action) {
    const { type, data } = action
    switch (type) {
        case 'increment':
            return preState + data
        case 'decrement':
            return preState - data
        default:
            return preState
    }
}

10.1.3 state变化后触发render

index.js

bash 复制代码
// 检查redux中状态的变化,只要有变化就会执行回调
import store from './redux/store'
store.subscript(() => {
  ReactDOM.render(<App />, document.getElementById('root'))
})

10.2 核心Api

  • createStore
  • getState

11.react-redux

12.hooks(解决函数式组件的state,ref)

12.1 useState

useState函数参数表示默认值,返回数组第一项是状态值,第二项是修改方法

bash 复制代码
import React, { useState } from "react"
// 调用1+n次
function Home(props) {
    // 第一次调用就存储了,后续调用Home的时候不会重置成0
    const [count, setCount] = useState(0)
    const [obj, setObj] = useState({
        myName: 'name1',
        age: 18
    })
    function changeCount() {
        // setCount(count+1)
        setCount((count) => count + 1)
    }
    function changeName() {
        setObj({
            ...obj,
            myName: 'name2'
        })
    }
    return (
        <div>
            我是函数式组件
            <div>
                state方式1:{count}
                <button onClick={changeCount}> 点我修改state </button>
                <br />
                state方式2:{obj.myName} {obj.age}
                <button onClick={changeName}> 点我修改state </button>
            </div>
        </div>
    )
}

export default Home;

12.2 useEffect(模拟生命周期)

接受两个参数:回调函数,监听数组

  • 第一个参数:
    返回函数相当于componentWillOnmount
  • 第二个参数:
    如果没有传,监听所有变化执行。
    如果传空数组,那回调指挥在第一次render后执行。
    如果传了数组项,就是监听对应数组项的变化。
bash 复制代码
// 第二个参数空数组相当于componentDidMount, componentDidUpdate
useEffect(() => {
    let timer = setInterval(() => {
        setCount((count) => count + 1)
    }, 1000)
    // useEffect返回的函数相当于componentWillOnmount
    return () => {
        clearInterval(timer)
    }
}, ['count'])

12.3 useRef

bash 复制代码
const myRef = useRef()
function getRefValue() {
    alert(myRef.current.value)
}
return (
	<div>
		<input ref={myRef}></input>
		<button onClick={getRefValue}> 点我弹出input的值 </button>
	</div>
)

13.扩展

13.1 组件懒加载

使用的时候在加载

bash 复制代码
import React, { lazy } from 'react'
const Home = lazy(() => import('./Home'))

13.2 Fragment

Fragment标签不会编译到dom中

bash 复制代码
<Fragment></Fragment>
// 或者使用空标签,空标签不能传递属性,Fragment可以传key属性
<></>

13.3 Context(祖孙组件通信)

Context API 用于在组件树中共享全局数据,避免了通过层层传递 props 的繁琐操作。

  1. createContext.Provider +useContext
bash 复制代码
const MyContext = React.createContext('default');
class App extends React.Component {
  render () {
    return (
      <MyContext.Provider value={{ color: 'red' }}>
        <Child />
      </MyContext.Provider>
    ); 
  }
}
bash 复制代码
const value = React.useContext(MyContext);
  1. createContext.Consumer

13.4 错误边界(Error Boundaries)

错误边界是一种用于捕获子组件渲染过程中发生的错误,并展示备用 UI 的机制。componentDidCatch捕获异常

bash 复制代码
componentDidCatch(error, info) {
    this.setState({ hasError: true });
}

13.4 PureComponent

默认实现的shouldComponentUpdate方法中自动进行浅比较props和state,从而判断是否需要重新渲染组件。Component 的shouldComponentUpdate默认就是true

相关推荐
崔庆才丨静觅10 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606111 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅12 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment12 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅12 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊12 小时前
jwt介绍
前端
爱敲代码的小鱼12 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax