• react项目配置(类组件、函数式组件)


    类组件

    1、事件绑定

    class App extends React.Component {
    
        // 定义事件
        handleClick1(val, e) {
        	// 阻止默认行为
            e.preventDefault();
    
            //阻止冒泡
            e.stopPropagation();
            
            console.log(val, e);
        }
    
        // 定义事件第二种方式
        handleClick2(val3, e) {
            console.log(val3);
        }
    
        render() {
            return (
                <div className={style.App}>
                    <button onClick={this.handleClick1.bind(this, "传参数")}>事件绑定</button>
                    <button onClick={(e) => this.handleClick2(11, e)}>事件绑定第二中方式</button>
                </div>
            );
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注意:react中阻止冒泡和默认行为和原生是一样的 e.preventDefault(); e.stopPropagation();

    2、setState

    1. setState 是浅合并 (Object.asign), 所以在更新 state 状态时,如果是对象,一定要展开再合并新的数据
    state = {
    	obj: {
    		a: 1,
    		b: 2,
    		c: 3
    	}
    }
    setState({
    	obj: {
    		...this.state.obj,
    		b: 5
    	}
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. setState 在修改 list 数组的时候,如果是 React.Component 可是直接在数据的基础上修改,如果是 React.PureComponent ,就只能深拷贝一份数组再进行修改,因为 PureComponent 对比的是地址值
    2. 多次 setState render只会走一次
    3. 在类组件中 React.Component 下,setState 走一次, 就会render 一次页面更新,所以尽量使用 React.PureComponent
    4. setState 是异步的,取值要在第二个参数里面
    setState({
    	msg: "修改msg的值"
    }, () => {
    	this.state.msg  // 取值
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3、组件通讯

    react 中父组件传值给子组件 和 子组件传值给父组件,都是通过 props 来实现的

    父组件给子组件传值,父组件给子组件传递属性即可

    // 父组件中
     render() {
          return <div>
              <Son name="父传值给子"></Son>
          </div>
      }
    
    // 子组件中接值
    this.props.name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    子组件传值给父组件,父组件给子组件传递方法即可

    // 父组件中
    getChildValue(val) {
    	console.log("父组件拿到子组件的值", val)
    }
    
    render() {
       return <div>
            <Son onGetChildValue={this.getChildValue.bind(this)}></Son>
        </div>
    }
    
    // 子组件中
    handle() {
         this.props.onGetChildValue("子组件的值传给父组件")  // 子组件拿到父组件传过来的方法直接调用,把值传过去
     }
     
     render() {
         return <div>
             <button onClick={this.handle.bind(this)}>点击给父组件值</button>
         </div>
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    子组件接值验证和默认值的定义

    // props 验证值的类型 和 默认值
    Son.propTypes = {
        name: (props) => {
            if(typeof props.name !== "string") {
                return new Error("期望一个字符串")
            }
            return null
        }
    }
    Son.defaultProps = {
        name: "默认值"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    子组件接值验证借助第三方库

    // 1、下载 proptypes
    yarn add proptypes
    
    // 2、引用 
    import propType from "proptypes"
    
    // 子组件接值校验 (使用)
    Son.propTypes = {
    	name: propType.string,  // 校验字符串
    	age: propType.number,   // 校验数字
    	list: propType.array,   // 校验数组
    	obj: propType.object    // 校验对象
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4、插槽

    react中的插槽的使用也是 props

    // 1、默认插槽
    父组件
     render() {
       return <div>
            <Slot>
                <div>before</div> // 需要在子组件展示的内容
            </Slot>
        </div>
    }
    子组件
     render() {
       const { children } = this.props
        return <div>
            {children}
        </div>
    }
    
    
    
    
    // 2、具名插槽
    父组件
    render() {
        return <div>
            <Slot>
                <div data-id="before">before</div>  // 父组件传过去两处在子组件需要展示的内容
                <div data-id="after">after</div>
            </Slot>
        </div>
    }
    
    子组件占位,展示父组件的内容
     render() {
     	// 子组件从 props 得到 父组件传进来的 自定义属性为 data-id, 然后判断展示在不同的位置
       const { children } = this.props
        let beforeVNode, afterNode
        children.forEach(v => {
            if("before" === v.props['data-id']) {
                beforeVNode = v
            }else{
                afterNode = v
            }
        })
        return <div>
            {beforeVNode}  // 虚拟Dom用插值表达式来解析
            Slot
            {afterNode}
        </div>
    }
    
    
    // 3、作用域插槽 (借助的就是子传值给父组件)
    父组件
    render() {
       return <div>
            <Slot customClick={(val) => console.log(val)}></Slot>
        </div>
    }
    
    子组件
     render() {
       return <div>
            <button onClick={() => this.props.customClick(this.state.msg)}>作用域插槽</button>
        </div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    5、样式隔离

    创建 xxx.module.scss, 在jsx引入

    // 在js中
    import style from "./xxx.module.scss"
    render() {
    	return <div className={ style.box }>
    		111
    	</div>
    }
    // css中
    .box{
    	.....
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6、ref 的使用 (相当于函数式组件中的 useRef)

    ref 获取dom

    const div1 = React.createRef()  // 定义的 div1 和标签中的 ref 的值是一样的
    
    componentDidMount() {
    	console.log(div1)  // 获取 dom
    }
    
    render() {
    	return <div>
    		<div ref={div1}>111</div>
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    ref 获取组价实例

    const divComponent = React.createRef()  // 定义的 divComponent 和标签中的 ref 的值是一样的
    
    componentDidMount() {
    	console.log(divComponent)  // 获取组件实例
    }
    
    render() {
    	return <div>
    		<Son ref={divComponent}></Son>
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    函数式组件

    1、函数式组件没有生命周期
    2、函数式组件没有 this
    3、函数式组件通过 hook 来完成各种操作
    4、函数式组件本身的函数体相当于 render 函数
    5、props 在函数的第一个参数接受

    7、定义变量,修改变量

    import { useState } from "react"
    let [msg, setMsg] = useState('')  // 定义msg变量
    // 修改msg变量
    function changeMsg() {
    	setMsg('修改msg变量的值')
    }
    
    return <div>
    	{ msg }  // 使用变量
    	<button onClick={() => changeMsg()}>修改变量</button>
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    8、useEffect 副作用函数

    1、不传第二个参数 = componentDidMount 和 componentDidUpdate
    2、第二个参数传空数组 = componentDidMount
    3、第二个参数数组里面放某个数据 = watch 监听
    4、第一个参数函数体里面返回值是一个方法 = componentDidUnMount

    useEffect(function() {}, [])
    
    • 1

    9、useMemo

    useMemo 类似于 vue 中的计算属性, 第二个参数和 useEffect 的参数用法是一样的

    // 1、定义常量的时候可以用 useMemo 包裹一下,表示只在创建的时候创建一次, 更新的时候就不创建了
    const computedObj = useMemo(function() {
       return {
            name: "张三",
            age: 18
        }
    }, [])
    
    // 2、当做计算属性来使用,依赖写在第二个参数的数组里面
    const computedObj = useMemo(() => msg + ":" + text, [msg, text])  // 表示只有 msg 和 text 两个变量改变的时候,useMemo 才会重新运行
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    10、useCallback

    包裹方法使用的hook,第二个参数和 useMemo、useEffect 规则是一样的

    11、useRef (相当于类组件的 createRef)

    import { useRef, useEffect } from "react"
    const div1 = useRef()
    useEffect(() => {
    	console.log(div1.current)  // 获取dom节点
    }, [])
    return <div>
    	<div ref={div1}>111</div>
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    12、高阶组件(相当于vue中的mixins)

    高阶组件就相当于 vue 中的 mixins 混入, 说白了就是往使用高阶组件的组件的 props 里面 放一些公共的属性和方法

    在 utils 里面建一个高阶组件 HigherOrderComponent.jsx

    //  HigherOrderComponent.jsx
    import { useState } from "react"
    
    // 高阶组件的封装, Component 是:使用高阶组件的的原始组件,props 是原始组件本身的 props
    export default function HeightComponent(Component) {  // 暴露出去一个方法
        return function Heightsa(props) {   // 返回一个方法
    
            // 高阶组件封装的属性值(每个使用高阶组件的组件都可以使用)
            const [heightVal] = useState("高阶函数封装的属性")
    
            // 高阶组件封装的方法(每个使用高阶组件的组件都可以使用)
            const heightMethods = () => {
                console.log("高阶函数封装的方法");
            }
    
            return <>
            	// 把传进来的组件加上高阶组件包装之后的 props 返回出去,使用这个高阶组件的组件就有了上面的属性和方法
                <Component {...props} heightVal={heightVal} heightMethods={heightMethods}></Component>
            </>
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    组件的使用者

    import HeightComponent from "../utils/HigherOrderComponent.jsx"
    const App = (props) => {
    	const { heightVal, heightMethods } = props  // 拿到了高阶组件的属性和方法了
    	return <div>
    		App
    	</div>
    }
    export default HeightComponent(App)  // 只用高阶组件包装一下再暴露出去就可以了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    13、react中性能优化( useMemo、useCallback、React.memo )

    13-1、React.memo(相当于类组件的 PureComponent )

    memo 包裹子组件的引入,在父组件更新的时,子组件可以减少不必要的更新操作

    基本数据类型,只触发一次子组件的更新;引用数据类型变更会一直触发子组件的更新

    // 父组件
    import React, { memo } from "react"
    import Son from "./Son.jsx"
    const Sons = memo(Son)    // memo 包裹一下子组件的引入
    
    export default function Father() {
    	return <div>
    		<Sons></Sons>   // 子组件的使用位置
    	</div>
    }
    
    // 子组件
    import React from "react"
    export default function Son() {
     	return <div>
    		son
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    13-2、useMemo

    1、useMemo 用于计算属性
    2、useMomo 用于包裹不是 useState 定义的引用数据类型

    useMemo 用于计算属性

    export default function App() {
    	let obj = useMemo(() => ({name: "张三", age: 18}), [name])  // obj的变化依赖于 name 变量的变化而变化
    	return <div>
    		
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    定义引用数据类型的常量时,用 useMemo 包裹一下

    export default function App() {
    	let obj = useMemo(() => ({name: "张三", age: 18}), [])  // 这样定义的变量,即使传给子组件,也不会触发子组件的不必要更新
    	return <div>
    		
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    13-3、useCallback

    并不是所有的函数式组件在定义方法的时候都需要使用 useCallback , 这样是滥用 useCallback
    而是在父组件往子组件传递自定义方法的时候才需要,避免子组件不必要的渲染

    export default function App() {
    	const func = useCallback(function() {
    		
    	}, [])
    	return <div>
    		<Son func={func}></Son>
    	</div>
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    13、react中的状态管理工具

    13-1、mobx的使用

    13-1-1、mobx5 + 类组件
    1. yarn add -D react-app-rewired customize-cra @babel/plugin-proposal-decorators
    2. 根目录创建 config-overrides.js 文件
    // config-overrides.js
    const { override, addDecoratorsLegacy } = require("customize-cra")
    module.exports = override(addDecoratorsLegacy())
    
    • 1
    • 2
    • 3
    1. 根目录创建 .babelrc 文件
    // .babelrc
    {
        "plugins": [
            [
                "@babel/plugin-proposal-decorators", 
                {"legacy": true}
            ]
        ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 修改 package.json
    "scripts": {
        "start": "react-app-rewired start",
        "build": "react-app-rewired build",
        "test": "react-app-rewired test"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以上4部就是配置装饰器

    1. yarn add -D mobx@5 mobx-react@5
    2. 按照模块化创建 store
    // 1、store 目录里面创建index.js 作为store  的根文件
    import MainStore from "./mainStore"       // 引入的模块化 store 文件
    import FooterStore from "./footerStore"   // 引入的模块化 store 文件
    import { configure } from "mobx"
    
    configure({
        enforceActions: "always"   // 开启严格模式
    })
    
    class Store {
        constructor() {
            this.MainStore = new MainStore(this)
            this.FooterStore = new FooterStore(this)
        }
    }
    export default Store
    
    
    // 2、index.js 平级创建 mainStore.js 文件
    import { action, observable, runInAction } from "mobx";
    
    class MainStore {
        constructor(store) {
            this.store = store;
        }
    
        // 定义数据
        @observable list = [
            {
                id: 1, name: "张三", age: 18
            },
            {
                id: 2, name: "李四", age: 18
            },
            {
                id: 3, name: "王五", age: 18
            }
        ]
    
        // 修改 mobx 中的数据
        @action.bound changeList(payload) {
            this.list = payload
        }
    
        // 异步修改mobx中的数据
        @action.bound asyncChangeList(payload) {
            setTimeout(() => {
                
                runInAction(() => {
                    this.list = payload
                })
                
            }, 1000)
        }
    }
    export default MainStore
    
    
    
    
    // 3、index.js 平级创建 footerStore.js 文件
    import { action, observable } from "mobx";
    
    class FooterStore {
        constructor(store) {
            this.store = store;
        }
    
    	// 定义变量
        @observable msg = "张三"
    
    	// 定义计算属性
        @computed get computedRelyOn() {
            return this.comRelyOn + "许潇"  // 定义的计算属性表示 comRelyOn 发生变化,computedRelyOn 就跟着变化
        }
    
    	// 修改变量
        @action.bound changeMsg() {
            this.msg = Math.random()
        }
    }
    export default FooterStore
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    1. 组件中使用和修改mobx中的数据
    import React from 'react'
    import Son from "../son/Son"
    import { inject, observer } from "mobx-react"
       
    @inject("MainStore", "FooterStore")   // 引入模块里面的数据到组件中
    @observer
    export default class Father extends React.Component {  // 注意,只能使用Component,不能使用 PureComponent
        // mobx修改数组
        changeList =() => {
            const { changeList, list } = this.props.MainStore
            const newList = [...list]
            newList.push({
                id: Date.now(),
                name: "许潇",
                age: Date.now()
            })
            changeList(newList)
        }
    
        // mobx修改字符串
        changeMsg = () => {
            const { changeMsg } = this.props.FooterStore
            changeMsg()
        }
      
        render() {
    
            const { MainStore, FooterStore } = this.props
    
            return <div>
                Father
                <h3>mobx中的list渲染</h3>
                <div>
                    {MainStore.list.map(v => (
                        <li key={v.id}>{v.name} -- {v.age}</li>
                    ))}
                </div>
                <button onClick={this.changeList}>通过增加mobx中的值来修改list数组</button>
    
    
                <h3>mobx中的字符串渲染</h3>
                <div>{FooterStore.msg}</div>
                <button onClick={this.changeMsg}>通过增加mobx中的值来修改msg字符串</button>
                <hr />
                <Son></Son>
            </div>
        }
    }
    
    // 异步修改 mobx 里面的状态
    import React from 'react'
    import { inject, observer } from 'mobx-react'
       
    @inject("MainStore")
    @observer
    export default class Son extends React.Component {
        changeList = () => {
        	// 要不修改 mobx 里面的值
            const { asyncChangeList, list } = this.props.MainStore
            const newList = [...list]
            newList.push({
                id: Date.now(),
                name: Date.now(),
                age: 22
            })
            asyncChangeList(newList)
        }
      
        render() {
            return <div>
                Son
    
                <button onClick={this.changeList}>异步修改mobx中的值是父组件的list数组重新渲染</button>
            </div>
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    13-1-2、mobx6 + 函数式组件
    1. yarn add mobx mobx-react-lite
    2. store/index.js 文件中
    import { useContext, createContext } from "react"
    // 引入的模块化 store
    import footerStore from "./footerStore"
    import headerStore from "./headerStore"
    
    class store {
        constructor() {
            this.headerStore = new headerStore(this)
            this.footerStore = new footerStore(this)
        }
    }
    
    const context = createContext(new store())
    
    export default function useStore() {
        return useContext(context)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1. store/headerStore.js 文件中
    // 模块化 headerStore.js 文件中
    import { makeAutoObservable, runInAction } from "mobx";
    
    export default class headerStore {
        constructor(store) {
            this.store = store;
            // 将所有的变量改成 装饰 @observable , 将所有的方法改成 @action , 将所有的 get 修饰的 改成 计算属性 @computed get 
            makeAutoObservable(this, {}, { autoBind: true })
        }
    
        // 定义字符串
        msg = "初始值"
        // 修改字符串
        changeMsg(payload) {
            this.msg = payload
        }
        // 依赖msg字符串的计算属性
        get replyMsg() {
            return this.msg + "徐小平"
        }
        // 异步修改数组
        changeList(list) {
            setTimeout(() => {
                runInAction (() => {  // 异步修改数据要写在 runInAction 方法里面
                    this.list = list
                })
            }, 1000)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    1. 组件中使用
    import { observer } from 'mobx-react-lite'  // observer 将整个方法包裹,store状态变化,包裹之后就监测到了
    import useStore from "../../store"   // 引入创建的 store/index.js 仓库
    
    export default observer(function App() {
    	
    	const { footerStore, headerStore } = useStore()  // 拿到了 store 仓库里面的数据和方法
    
    	useEffect(function() {
    		console.log(footerStore.属性)
    		console.log(footerStore.方法)
    	}, [])
    
    	return <div>
    		{footerStore.属性}
    	</div>
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. mobx6 持久化数据
    // 1、安装包
    yarn add -D mobx-persist-store
    
    // 2、在 store 模块化仓库中
    import { makeAutoObservable, runInAction, action } from "mobx";
    import { makePersistable, isHydrated } from "mobx-persist-store";
    
    export default class footerStore {
        constructor(store) {
            this.store = store;
            makeAutoObservable(this, {}, { autoBind: true })
            
    		// 以下是持久化仓库的配置
            makePersistable(this, {
                // 在构造函数内使用 makePersistable
                name: "UserStore", // 保存的name,用于在storage中的名称标识,只要不和storage中其他名称重复就可以
                properties: ["list"], // 要保存的字段,这些字段会被保存在name对应的storage中,注意:不写在这里面的字段将不会被保存,刷新页面也将丢失:get字段例外。get数据会在数据返回后再自动计算
                storage: window.localStorage, // 保存的位置:看自己的业务情况选择,可以是localStorage,sessionstorage
                // 。。还有一些其他配置参数,例如数据过期时间等等,可以康康文档,像storage这种字段可以配置在全局配置里,详见文档
            }).then(
                action((persistStore) => {
                    // persist 完成的回调,在这里可以执行一些拿到数据后需要执行的操作,如果在页面上要判断是否完成persist,使用 isHydrated
                    // console.log(persistStore);
                })
            );
        }
        // 注意这个字段的使用:在页面useEffect的时候,如果你没有添加依赖数组(初始化执行),那么你可能拿不到computed计算的数据(原因是这时候还没有persist结束),所以
        // 这个属性还是比较重要的,因为它可以在页面上做判断,当页面load完成,get数据计算完成之后,isHydrated会置为true
        get isHydrated() {
            return isHydrated(this);
        }
    
    
        // 定义数组
        list = [
            { id: 1, name: "张三" },
            { id: 2, name: "李四" },
        ];
        // 异步修改数组
        changeList(list) {
            setTimeout(() => {
                runInAction(() => {
                    this.list = list;
                });
            }, 1000);
        }
    }
    
    // 3、组件中使用和原来是一样的
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    14、react 中的 v6 版本的路由

    yarn add -D react-router-dom

    1、在index.js文件中:

    import { BrowserRouter } from "react-router-dom";
    root.render(
        <BrowserRouter>
            <App />
        </BrowserRouter>
    )
    // 这样所有的组件都可以使用路由,包括app.js组件
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、app.js文件

    import "./App.scss";
    import { Routes, Route } from "react-router-dom";
    import { lazy, Suspense } from "react";
    import { AuthRoute } from "../components/beforeEachRouter/AuthRoute";  // 类似于vue中的路由守卫,利用高阶组件
    import PrivateRouter from "../router/PrivateRouter";  // 根据数据库里面的数据生成路由表,权限控制
    
    // 路由懒加载 需要 Suspense 包裹
    const Login = lazy(() => import("../views/login/Login"));
    const Layout = lazy(() => import("./layout/Layout"));
    const NoPage = lazy(() => import('../views/NoPage/NoPage'));
    
    function App() {
        return (
            <Routes>
                <Route path="/login" element={
                        <Suspense fallback={<div>...</div>}>
                            <Login></Login>
                        </Suspense>
                    }>
                </Route>
                
                // AuthRoute 高阶组件,有token就进入系统,没有token进不去
                <Route path="/" element={<Suspense fallback={<div>...</div>}><AuthRoute><Layout /></AuthRoute></Suspense>}>
                    {PrivateRouter()}   // 权限路由
                    // 路由重定向,表示当前在 / 页面下,就自动跳转到 /index 页面
                    <Route path="/" element={<Navigate to="/index" />} />
                    <Route path="*" element={<Suspense fallback={<div>...</div>}><NoPage></NoPage></Suspense>}></Route>  // 404页面                       
                </Route>
    
            </Routes>
        );
    }
    
    export default App;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3、在需要展示的嵌套组件中使用

    <Outlet />
    
    • 1

    4、路由跳转传参(三种方式)

    const navigate = useNavigate()
    navigate('/page1')
    // 4-1、searchParams 传参
    navigate('/page1?name=张三&age=18')
        // 接参
    	let [searchParams, setSearchParams] = useSearchParams()
    	searchParams.get('name')
    	searchParams.get('age')
    
    
    // 4-2、params 传参
         // 路由表配置上
          {
            path: "/page1/:name/:age",//注意这里 可以占位多个
            element: <Page1 />
          }
          navigate('/page1/张三/18')
          // 接参
          const params = useParams()
          params.name
          params.age
    
    
    // 4-3、state 传参
    	navigate('/page1', {
    		state: { name: '张三', age: 18 },
    		replace: true
    	})
    	// 接参
    	const location = useLocation()
    	location.state.name
    	location.state.age
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    15、react-transition-group 动画使用

    15-1、单个元素使用

    // isShow 表示显示和隐藏  timeout 表示到时间卸载掉元素  unmountOnExit 卸载元素
    <CSSTransition in={ isShow } timeout={300} classNames='single' unmountOnExit>
       <div className={Style.box}></div>
    </CSSTransition>
    
    • 1
    • 2
    • 3
    • 4

    对应的css

    // 单个元素
    /* 入场动画之前 */
    .single-enter{
        opacity: 0;
        transform: translateY(300px);
    }
    /* 入场动画过程之后 */
    .single-enter-active{
        transition: 300ms;
        opacity: 1;
        transform: translateY(0px);
    }
    
    /* 出场动画之前 */
    .single-exit{
        opacity: 1;
        transform: translateY(0px);
    }
    /* 出场动画过程之后 */
    .single-exit-active{
        transition: 300ms;
        opacity: 0;
        transform: translateY(300px);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    15-2、列表使用

    <ul>
        <TransitionGroup>
            {list.map((v, index) => (
            	// CSSTransition 中的 key 要用数组中的唯一值,不要用索引,否则会出现离场动画问题
                <CSSTransition key={v.id} timeout={500} classNames="list-animate" appear={true} unmountOnExit>
                    <li className={Style.li1}>
                        <p className={Style.p1}>{v.name}</p>
                        <Button size='mini' onClick={() => handleDelete(index)}>删除</Button>
                    </li>
                </CSSTransition>
            ))}
        </TransitionGroup>
    </ul>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    对应的css

    // 列表动画
    .list-animate-enter{
        opacity: 0;
    }
    .list-animate-enter-active{
        opacity: 1;
        transition: all 0.5s;
    }
    .list-animate-exit{
        opacity: 1;
    }
    .list-animate-exit-active{
        opacity: 0;
        transition: all 0.5s;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    15-3、路由组件切换使用

    // 1、使用 SwitchTransition 组件包裹 CSSTransition 
    // 2、SwitchTransition 组件中 mode='out-in' 表示先离场在进入
    // 3、CSSTransition 组件中的 key 表示唯一值,所以用了 useLocation() 中的 key
    // 4、不要直接使用  , 要使用  const outlet = useOutlet() => {outlet} 代替
    
    <SwitchTransition mode='out-in'>
       <CSSTransition key={location.key} classNames="fade" timeout={500}>
            {outLet}
        </CSSTransition>
    </SwitchTransition>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对应的css

    .fade-enter {
    	opacity: 0;
    	transform: translateX(-50px);
    }
    .fade-enter-active {
    	opacity: 1;
    	transform: translateX(0%);
    	transition: all 500ms;
    }
    .fade-exit {
    	opacity: 1;
        transform: translateX(0);
    }
    .fade-exit-active {
    	opacity: 0;
        transform: translateX(-50px);
    	transition: all 500ms;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    16、react + v6 路由 权限控制

    代码地址: https://gitee.com/xu-xiao1/react-permissions

  • 相关阅读:
    JavaScript 各种小案例
    SQL基础语句
    竞赛 深度学习YOLOv5车辆颜色识别检测 - python opencv
    RPA能实现哪些功能,有什么特点!
    从零开始的 dbt 入门教程 (dbt core 开发进阶篇)
    MATLAB算法实战应用案例精讲-【图像处理】图像识别分类
    肠道病毒组识别早产儿坏死性小肠结肠炎发病前的特异性病毒特征
    Python包管理工具之pipenv
    php沿河农产品特卖网站的设计与实现毕业设计源码201521
    小程序js(正则表达式):文本框对手机号进行标准化规范
  • 原文地址:https://blog.csdn.net/weixin_43993776/article/details/133157000