React 知识点:基础语法、组件、React-Router、Redux

本文详细介绍了React的基础知识,包括React的特点、开发环境的搭建、核心语法如jsx、组件、事件处理和样式操作。同时,讲解了React的生命周期、Hooks的使用,如useState、useEffect和useContext,以及如何进行组件通讯和状态管理。此外,还涵盖了React Router的使用、Redux的状态管理和性能优化技巧。通过本文,读者可以全面了解并掌握React的实战技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、React介绍

1、特点:数据驱动、组件化、虚拟DOM

二、开发环境

1、方法一:引入js

(1)npm i react@17.0.0  react-dom@17.0.0  babel-standalone@6.26.0 

(2)按顺序引入下面三个js文件

 2、方法二:create React App脚手架工具创建项目

(1)安装集成环境

(2)创建项目和运行

3、方法三:webpack手动搭建

开始一个React项目(一)一个最简单的webpack配置_dengdengda的博客-优快云博客

三、核心基础

1、用法

2、jsx

(1)含义:

(2)规则:

3、操作属性

4、注释

5、操作样式

(1)行内样式

(2)类样式

6、操作事件

(1)注意事项:原生写法onClick中C要大写;事件处理函数名是个变量,用jsx写法;

7、Fragments  短语法:表示根元素,渲染后不会编译成其他元素

8、条件渲染

(1)注意事项:复杂的if语句,封装成函数,调用函数

9、列表渲染(map方法)

10、组件和props

(1)函数组件

(2)类组件(props 作为类对象子对象存在)

(3)使用

11、store(操作组件内部数据)

(1)类组件

注意:

*state可定义在constructor(){}内,也可以不定义在里面

*setState()是异步操作,若要等值更改好,在调用可使用promise方法包裹(例如商品列表加载更多)

12、类组件事件和this指向

(1)方法一:通过.bind改变this指向

(2)方法二:

注意:在constructor(){}里面定义变量,改变this指向

(3)方法三(箭头函数)

注意:如果回调函数通过props传入子组件时,这些组件可能会进行重新渲染

(4)方法四(事件处理函数定义为箭头函数,推荐使用)

注意:不传参时,绑定事件不用套一层箭头函数,传参时,绑定事件要套一层箭头函数

13、类组件改变状态值(类似于微信小程序原生写法)

14、阻止事件默认行为

四、组件通讯

1、props

(1)值只读,不能修改

(2)任意类型数据可传(字符串、jsx、数组、对象等)

2、插槽概念

(1)父组件

(2)子组件

3、子传父

(1)父组件

(2)子组件

4、兄弟之间

子组件A—父组件—子组件B

5、跨组件通讯(App组件向任意一个下层组件传递数据)

(1)利用Context实现

(2)src文件夹下创建utils文件夹,utils文件夹内创建utils.js文件,文件内创建Context对象,导出Provider和Consumer对象

(3)在index.js文件中引入utils.js暴露的Provider,Provider包裹根组件,并定义要传递的内容

(4)下层组件中引入utils.js中暴露的Consumer,接收根组件传递的值

6、Refs(允许访问DOM节点或render方法中创建的React元素-子组件)

(1)在类组件内部创建Refs对象,可多次创建,且只能在类组件中创建

五、生命周期

1、网址:React lifecycle methods diagram

2、生命周期视图

 3、生命周期钩子函数的触发时间和作用

(1)挂载阶段

注意事项:

*app.js文件内App组件不要用严格模式包裹,否则初始化时,componentDidMount会执行2次

 (2)更新阶段

 (3)卸载阶段

六、Hooks(只能在函数组件中使用)

1、定义

(1)一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数

(2)常用的Hooks:setState() setEffect()  setRef() setContext()

2、特点

(1)在组件之间复用状态逻辑, 无需修改组件结构

(2)将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分

(3)不编写 class 的情况下使用 state 以及其他的 React 特性

3、useState

(1)使用

(2)语法(useState内可定义数组、对象、数值、字符串等数据类型)

4、useEffect

(1)定义:

*可以让在函数组件中执行副作用操作

*副作用:函数组件主要作用是通过数据渲染UI界面,除了这个之外的操作就是副作用,例如:ajax请求、手动修改dom、 localstorage操作等

(2)语法:

*方式一:useEffect(()=>{}) //第一次进入执行,每次更新都会执行

*方法二:useEffect(()=>{},[]) // 第一次进入时执行

*方法三:useEffect(()=>{},[count]) //第一次进入时执行,或者count变化,执行回调函数(类似watch监听器)

*方法四:useEffect(()=>{ return ()=>{} }) // 组件销毁执行return中代码(可以加[],可以不加[])

5、useContext(跨组件通讯)

(1)utils.js中创建MessageContext实例对象

(2)App.js中引入MessageContext

(3)下层组件中引入MessageContext

6、useRef

7、useMemo(性能优化)

(1)用法:依赖的值变化,才执行(且需要返回一个值时)

8、useCallback

(1)作用:缓存函数,只执行一次,可解决React.memo中子组件接收函数而父组件渲染,子组件跟着一起渲染问题

(2)使用

七、高阶组件

1、定义

(1)是一个函数

(2)接收一个组件参数,返回一个新的组件

2、React.memo高阶组件(只有组件内状态变化才执行)

(1)使用方法(包裹子组件)

(2)使用场景:更新父组件时,子组件不更新

(3)组件更新的条件:setState、props

(4)注意事项:

*若父组件传给子组件一个函数,父组件渲染,子组件跟着一起渲染;

*原因:函数是复杂数据类型,父组件更新,重新生成新的函数对象

*解决方法:使用useCallback()包裹传递的函数

八、fetch(内置网络请求方法,直接使用,get方法可以不写出来)

九、React路由创建

1、下载react-router

npm install react-router-dom  --save

2、导出路由相关组件

(1)const{BrowserRouter、HashRouter、Routes、Route、NavLink、Navigate} from ’react-router-dom‘

(2)路由模式:HashRouter 和 BrowserRouter

(3)路由规则:Routes和Route

(5)重定向:Navigate

3、使用

十、嵌套路由

1、定义子路由(路径不要有'/')

2、子路由展示:父路由对应组件内使用Outlet展示,若父组件内要定义NavLink跳转,则路径要加上父路由的路径

十一、全局匹配404

1、}>

十二、编程导航与传参

1、编程式导航-跳转

(1)作用:通过js编程的方式进行路由页面跳转,比如登录页到关于页

(2)语法

*导入useNavigate钩子函数

*执行useNavigate钩子函数得到跳转函数

*执行跳转函数完成跳转(默认是push方式跳转,可定义replace方式)

2、动态传参

(1)跳转时路径带参数

(2)接收参数(useSearchParams())

十三、定义组件局部css样式

1、定义局部样式原因:组件的全局样式会互相影响

2、定义方法

(1)css命名为index.module.css     //主要是要带module字段

(2)index.js中引入样式文件   import   styles  from  ’css文件路径‘

(3)使用(两种方式)

十四、高阶组件(定义移动端TabBar)

1、定义首页、分类、购物车、我的和TabBar组件

2、定义首页、分类、购物车、我的路由(App.js中)

(1)注意:传子组件的方式:

3、TabBar组件内定义高阶组件

十五、Redux 状态管理

1、特点:

(1)集中式存储管理应用的所有组件的状态

(2)保证状态以一种可预测的方式发生变化

(3)简化Redux组件间通讯

2、核心概念与理论

(1)state: state对象包含所有数据。

(2) Store :  Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。

(3) Action : Action 就是 View 发出的通知,表示 State 应该要发生变化了, Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置. 由组件store.dispatch(‘action’, payload)触发。

(4) Reducer: Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。(state,action)=> newState;

(5) dispatch:store操作行为触发方法,是执行action的方法。 store.dispatch(‘action’, payload)

(6)subscribe: Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。 只要把 View 的更新函数(对于 React 项目,就是组件的render方法或setState方法)放入listen,就会实现 View 的自动渲染。

(7) getState(): store.getState()获取state状态数据

3、安装

(1)npm install redux --save

4、基础使用

(1)新建store文件夹,文件夹下新建store,js文件

*注意:reducer中只能执行同步任务

(2)组件内引入暴露的store

 *获取值:store.getState().count

*改变值:store.dispatch({type:'minus'}  //dispatch中的对象是action对象

*注意:需要使用store.subscribe()去监听state内值的变化,然后使用useState()去更改值,从而刷新界面,与useEffect(()=>{ },[ ])配合使用,只启动一次监听器,就会永久监听

5、combineReducers(合并Reducers、适用于store.js里面有多个reducers时)

(1)使用:const reducer = combineReducers({counterReducer,cartReducer})

(2)组件中取值:let list = store.getState().cartReducer.list

6、vueX与reduX区别

(1)vuex中直接操作state状态数据是在mutations选项中,mutation中每个操作定义成一个方法;redux中直接操作state状态数据是在reducer中,只有一个函数,不同操作通过action动作的type区分

(2)reducer函数中操作state,先拷贝一份,更改之后返回一个新state

十五、Redux  Toolkit库(可以直接更改state内的值,不用拷贝一份再修改)

1、安装

npm i @reduxjs/toolkit

2、使用

(1)store文件夹下定义xx.js文件内,使用导入的createSlice创建对象(state的名字必须是: initialState),内含接收参数的写法,获取组件传入的参数:action.payload

(2)store文件夹下定义的index.js文件内:集成多个reducers

(3)组件内使用

*注意:需要使用store.subscribe()去监听state内值的变化,然后使用useState()去更改值,从而刷新界面

十六、React-Redux库(使用hooks函数简化组件内取值和改变值的操作)

1、安装

npm i react-redux

2、在index.js文件中导入Provider包裹App组件,还要导入暴露的store(让useSelector()与store建立联系,Provider透传store)

3、组件内导入useSelector,useDispatch

(1)注意:useSelector()会监听数据变化从而刷新界面,不用useState()更改值在刷新界面

(2)import { useSelector,useDispatch } from 'react-redux'

4、组件内使用

(1)获取值

const cartList= useSelector(state=>state.cart.list)

(2)修改值

const dispatch = useDispatch()

dispatch(addCart(product))

十七、Redux中进行异步任务操作(必须是在安装了Redux Toolkit库才行)

1、store文件夹下的xxx.js文件内

(1)引入createAsyncThunk(),创建对象,并暴露出去,在组件中使用(系统会自动封装成promise,返回三种状态:成功、加载、失败)

(2) extraReducers(builder){ }中获取异步任务返回的值,进行保存

2、组件中发起异步请求

(1)引入createAsyncThunk()所创建的暴露了的对象

(2)使用useDispatch进行传参(传入异步任务所返回的值)


一、React介绍

1、特点:数据驱动、组件化、虚拟DOM

二、开发环境

1、方法一:引入js

(1)npm i react@17.0.0  react-dom@17.0.0  babel-standalone@6.26.0 

(2)按顺序引入下面三个js文件

 2、方法二:create React App脚手架工具创建项目

(1)安装集成环境

*安装插件

*编写代码rcc 就可以生成有状态的组件代码块

(2)创建项目和运行

npx create-react-app my-app
cd my-app
npm start

3、方法三:webpack手动搭建

开始一个React项目(一)一个最简单的webpack配置_dengdengda的博客-优快云博客

三、核心基础

1、用法

  <div id="app">

    </div>

    <script type="text/babel">
        // ReactDOM  render(react元素,根节点)  
        ReactDOM.render(<h2>helloworld</h2>,document.getElementById('app'))
    </script>

2、jsx

(1)含义:

JSX 全称 JavaScript XML ,是一种扩展的 JavaScript 语言, 它允许 HTML 语言直接写在 JavaScript 语言中,不加任何引号,这就是 JSX 语法。 它允许 HTML 与 JavaScript 的混写。

(2)规则:

- {} 内容做为javascript代码解析

- () 作用html标签解析 - 必须有根节点 - 单标签不能省略结束标签。/>

<img src="  "    alt=" "  />

- 必须有根节点

<div>
     <p>{props.user.name}</p>
     <p>{props.user.age}</p>
     <p>{props.title}</p>
</div> 

- JSX 允许直接在模板中插入一个 JavaScript 表达式(如:三目运算)

3、操作属性

const url="路径"

<img src={url} />

4、注释

{/*注释:操作行内样式*/}

5、操作样式

(1)行内样式

const sty = {
            color: 'red',
            fontSize:'28px'
        }

<p style={ {color:'blue'} }> 样式简写 </p>

<h2 style={sty}>样式操作示例</h2>

(2)类样式


 <style>
        .m-style{
            width: 100px;
            height: 100px;
            background-color: skyblue;
        }
 </style>

<p className="m-style">类样式</p>

6、操作事件

(1)注意事项:原生写法onClick中C要大写;事件处理函数名是个变量,用jsx写法;

 
function bindClick(){
            console.log('触发事件');
        }

 {/* 操作事件 */}
 <button type="button" onClick={bindClick}>按钮</button>

7、Fragments  短语法:表示根元素,渲染后不会编译成其他元素

 <React.Fragment>
     {/* 操作内容  */}
     <h2>{title}</h2>
 </React.Fragment>
 

8、条件渲染

(1)注意事项:复杂的if语句,封装成函数,调用函数

  <div id="app">

    </div>

    <script type="text/babel">
        let age = 19

        function getAgeMessage() {
            if (age > 18) {
                return <h2>成年</h2>
            } else if (age == 18) {
                return <h2>18岁</h2>
            } else {
                return <h2>未成年</h2>
            }
        }

        const element = (
            <div>
                {age > 18 ? '成年人' : '未成年'}
                {age > 18 ? (<h2>成年人</h2>) : (<h2>未成年人</h2>)}
                {age > 18 && <p>逻辑与条件处理</p>}

                {getAgeMessage()}
            </div>
        )


        ReactDOM.render(element, document.getElementById('app'))
    </script>

9、列表渲染(map方法)

const list = [
            { id: 1001, name: 'javascrip编程', price: 18.89 },
            { id: 1002, name: 'vue编程', price: 58.89 },
            { id: 1003, name: 'react编程', price: 98.89 },
        ]

        // let arr = list.map(item=><li>{item.id} {item.name} {item.price}</li>)

        const element = (
            <div>
                <ul>
                    {/*
                    <li>1001  javascrip编程  18.89</li>
                    <li>1002  javascrip编程  18.89</li>
                    <li>1003  javascrip编程  18.89</li>*/}
                    {list.map(item => <li>{item.id} {item.name} {item.price}</li>)}
                </ul>

                <table className="y-table">
                    {
                        list.map((item,index) => (
                            <tr key={index}>
                                <td>{item.id}</td>
                                <td>{item.name}</td>
                                <td>{item.price}</td>
                            </tr>
                        ))
                    }

                </table>

            </div>
        )

10、组件和props

(1)函数组件

 function Welcome(props) {
            return (
                <div>
                    <h2>组件</h2>
                    <p>{props.title}</p>
                    <p>{props.content}</p>
                </div>
            )
        }

(2)类组件(props 作为类对象子对象存在)

class WelcomeTwo extends React.Component {
            constructor(){
                super()
            }
            render() {
                return (
                    <div>
                        <h2>组件</h2>
                        <p>{this.props.title}</p>
                    </div>
                )
            }
        }

(3)使用

ReactDOM.render(<WelcomeTwo title="类组件" content="这是函数组件学习"/>, document.getElementById('app'))

11、store(操作组件内部数据)

(1)类组件

注意:

*state可定义在constructor(){}内,也可以不定义在里面

*setState()是异步操作,若要等值更改好,在调用可使用promise方法包裹(例如商品列表加载更多)

class WelcomeTwo extends React.Component {
            // constructor(){
            //     super()
            // }
            //定义组件内部状态数据
            state = {
                user: {
                    name: 'jack',
                    age: 18
                },
                content: '这是组件内部数据'
            }
            render() {
                return (
                    <div>
                        <h2>组件</h2>
                        <p>{this.props.title}</p>
                        <p>{this.state.content}</p>
                        <p>{this.state.user.name}</p>
                    </div>
                )
            }
        }

12、类组件事件和this指向

(1)方法一:通过.bind改变this指向

{/*事件处理函数中绑定this指向*/}
 <button onClick={this.onConfirm.bind(this)}>确定</button>

onConfirm() {
                let value = this.state.inputValue
                console.log('onConfirm >>>', value);
            }

(2)方法二:

注意:在constructor(){}里面定义变量,改变this指向

constructor() {
                super()
                this.state = {
                    inputValue: 'javascript高级编程',
                    count: 0
                }
                // 绑定this
                this.onPlus = this.onPlus.bind(this)
        }


{/* 事件绑定,初始化时绑定this */}
 <button onClick={this.onPlus}>加一</button>
onPlus() {
      console.log('plus ', this.state.count);
   }

(3)方法三(箭头函数)

注意:如果回调函数通过props传入子组件时,这些组件可能会进行重新渲染

{/* 箭头函数实现 */}
  <button onClick={ ()=>{this.onMinus(100)} }>减一</button>

onMinus(age) {
                console.log('age ',age);
                console.log('minus ', this.state.count);
            }

(4)方法四(事件处理函数定义为箭头函数,推荐使用)

注意:不传参时,绑定事件不用套一层箭头函数,传参时,绑定事件要套一层箭头函数

 {/* 事件绑定写法 */}
  <button onClick={()=>{this.onDouble(200)}}>双倍</button>

onDouble = (age)=>{
                console.log('age ',age);
                console.log('onDouble ',this.state.count);
            }

13、类组件改变状态值(类似于微信小程序原生写法)

 plus=()=>{
                let count = this.state.count
                count++
                this.setState({
                    count
                })
            }

14、阻止事件默认行为

event.preventDefault()

四、组件通讯

1、props

(1)值只读,不能修改

(2)任意类型数据可传(字符串、jsx、数组、对象等)

2、插槽概念

(1)父组件

<SonA emit={<p>这是jsx参数</p>}/>

(2)子组件

{props.emit}

3、子传父

(1)父组件

<SonA emit={ (msg)=>{this.getMessage(msg)} }/>
getMessage = (msg)=>{
        console.log('函数参数getMessage',msg) 
    }

(2)子组件

 <button type="button" onClick={ ()=>{props.emit('这是子组件参数')} }>确定</button>

4、兄弟之间

子组件A—父组件—子组件B

5、跨组件通讯(App组件向任意一个下层组件传递数据)

(1)利用Context实现

(2)src文件夹下创建utils文件夹,utils文件夹内创建utils.js文件,文件内创建Context对象,导出Provider和Consumer对象

// 创建Context对象,导出Provider和Consumer对象
	
import React from 'react'
export const {Provider,Consumer} = React.createContext()

(3)在index.js文件中引入utils.js暴露的Provider,Provider包裹根组件,并定义要传递的内容

root.render(
	<Provider value="这是根数据">
		<App />
	</Provider>
)

(4)下层组件中引入utils.js中暴露的Consumer,接收根组件传递的值

 <Consumer>{ (value)=><p>{value}</p> }</Consumer>

6、Refs(允许访问DOM节点或render方法中创建的React元素-子组件)

(1)在类组件内部创建Refs对象,可多次创建,且只能在类组件中创建

export default class ParentRefs extends Component {
    constructor(){
        super()
        this.state={
            message:''
        }
        // this.myRef = React.createRef() // 1.创建myRef实例对象
        this.sonRef = React.createRef()
    }
	render() {
		return (
			<div>
				<h2>refs获取组件实例或Dom节点</h2>
                {this.state.message}
				{/* <div id="d1" ref={this.myRef} >refs操作dom节点</div> */}

                <SonA ref={this.sonRef}/>
				<button type="button" onClick={this.onConfirm}>
					确定
				</button>
			</div>
		)
	}

	onConfirm = () => {
		// 获取dom节点内容
		// const divEle = document.getElementById('d1')
        // divEle.innerHTML = '这是新值'
        // const divEle = this.myRef.current
        // divEle.innerHTML = '这是refs改变值'

        const sonA = this.sonRef.current
        console.log('sonA ',sonA);
        this.setState({message:sonA.state.content})
	}
}

五、生命周期

1、网址:React lifecycle methods diagram

2、生命周期视图

 3、生命周期钩子函数的触发时间和作用

(1)挂载阶段

注意事项:

*app.js文件内App组件不要用严格模式<React.StrictMode></React.StrictMode>包裹,否则初始化时,componentDidMount会执行2次

 (2)更新阶段

 (3)卸载阶段

六、Hooks(只能在函数组件中使用)

1、定义

(1)一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数

(2)常用的Hooks:setState() setEffect()  setRef() setContext()

2、特点

(1)在组件之间复用状态逻辑, 无需修改组件结构

(2)将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分

(3)不编写 class 的情况下使用 state 以及其他的 React 特性

3、useState

(1)使用

import React, { useEffect, useState } from 'react'

(2)语法(useState内可定义数组、对象、数值、字符串等数据类型)

const [count,setCount] = useState(0)
const [user,setUser] = useState({name:'jack',age:18})

4、useEffect

(1)定义:

*可以让在函数组件中执行副作用操作

*副作用:函数组件主要作用是通过数据渲染UI界面,除了这个之外的操作就是副作用,例如:ajax请求、手动修改dom、 localstorage操作等

(2)语法:

*方式一:useEffect(()=>{}) //第一次进入执行,每次更新都会执行

*方法二:useEffect(()=>{},[]) // 第一次进入时执行

*方法三:useEffect(()=>{},[count]) //第一次进入时执行,或者count变化,执行回调函数(类似watch监听器)

*方法四:useEffect(()=>{ return ()=>{} }) // 组件销毁执行return中代码(可以加[],可以不加[])

5、useContext(跨组件通讯)

(1)utils.js中创建MessageContext实例对象

export const MessageContext = React.createContext()

(2)App.js中引入MessageContext

import { MessageContext } from '../utils/util'

<MessageContext.Provider value='测试'>
				<Root />
</MessageContext.Provider>

(3)下层组件中引入MessageContext

const message = useContext(MessageContext)
 <p>{message}</p>

6、useRef

 const inputRef = useRef(null) //创建ref对象

    const setFocus = ()=>{
        inputRef.current.focus()
    }

	return (
		<div>
			<h2>TextInputFocus</h2>
			<input type="text" ref={inputRef}/>
			<button type="button" onClick={ setFocus }>获取焦点</button>
		</div>
	)

7、useMemo(性能优化)

(1)用法:依赖的值变化,才执行(且需要返回一个值时)

const [user, setUser] = useState({ gender: 0, age: 18 })

const formateGennder = gender => {
		console.log('222222')
		if (gender === 0) {
			return '男'
		} else {
			return '女'
		}
	}

//使用useMemo优化
	const gender = useMemo(() => {
		return formateGennder(user.gender)
	}, [user.gender])

//展示
<p>{gender}</p>

8、useCallback

(1)作用:缓存函数,只执行一次,可解决React.memo中子组件接收函数而父组件渲染,子组件跟着一起渲染问题

(2)使用

  const setNum = useCallback(()=>{
        console.log('函数参数');
    },[])

七、高阶组件

1、定义

(1)是一个函数

(2)接收一个组件参数,返回一个新的组件

2、React.memo高阶组件(只有组件内状态变化才执行)

(1)使用方法(包裹子组件)

const 新组件=React.memo(组件)
import React, { memo } from 'react'

export default memo(function Son(props) {
	console.log('son >>>>>')
	return (
		<div>
			<h2>Son</h2>
            {/* <p>{num}</p> */}
		</div>
	)
})

(2)使用场景:更新父组件时,子组件不更新

(3)组件更新的条件:setState、props

(4)注意事项:

*若父组件传给子组件一个函数,父组件渲染,子组件跟着一起渲染;

*原因:函数是复杂数据类型,父组件更新,重新生成新的函数对象

*解决方法:使用useCallback()包裹传递的函数

八、fetch(内置网络请求方法,直接使用,get方法可以不写出来)

fetch('后端网址url')
			.then(res => {
				return res.json()
			})
			.then(data => {
				console.log('data ', data)
				let { resultCode, resultInfo } = data
				if (resultCode === 1) {
					setList(resultInfo.list)
				}
			})
			.catch(error => {
				setError(error)
			})

九、React路由创建

1、下载react-router

npm install react-router-dom  --save

2、导出路由相关组件

(1)const{BrowserRouter、HashRouter、Routes、Route、NavLink、Navigate} from ’react-router-dom‘

(2)路由模式:HashRouter 和 BrowserRouter

(3)路由规则:Routes和Route

(5)重定向:Navigate

3、使用

<BrowserRouter>
        {/* 点击跳转,类似a标签 */}
			<NavLink to="/nba">Nba</NavLink> | <NavLink to="/news">新闻</NavLink>
				{/* Routes 路由容器 */}
				<Routes>
                       {/* Navigate 重定向 */}
					<Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
					<Route path="/login" element={<Login/>}></Route>
					<Route path="/home" element={<Home/>}></Route>
					{/* 路由规则 Route  path路径  element元素 */}
					<Route path="/nba" element={<Nba />}></Route>
					<Route path="/news" element={<News />}>
						{/* 嵌套路由  index默认路由*/}
						<Route index element={<Fun />}></Route>
						<Route path="sports" element={<Sports />}></Route>
					</Route>
					{/* 路由找不到404处理 */}
					<Route path="*" element={ <NotFund/>}></Route>
				</Routes>
			</BrowserRouter>

十、嵌套路由

1、定义子路由(路径不要有'/')

<BrowserRouter>
				{/* Routes 路由容器 */}
				<Routes>
					<Route path="/news" element={<News />}>
						{/* 嵌套路由  index默认路由*/}
						<Route index element={<Fun />}></Route>
						<Route path="sports" element={<Sports />}></Route>
					</Route>
				</Routes>
			</BrowserRouter>

2、子路由展示:父路由对应组件内使用Outlet展示,若父组件内要定义NavLink跳转,则路径要加上父路由的路径

十一、全局匹配404

1、<Route path="*" element={ <NotFund/>}></Route>

十二、编程导航与传参

1、编程式导航-跳转

(1)作用:通过js编程的方式进行路由页面跳转,比如登录页到关于页

(2)语法

*导入useNavigate钩子函数

import { useNavigate } from 'react-router-dom'

*执行useNavigate钩子函数得到跳转函数

const navigate = useNavigate()

*执行跳转函数完成跳转(默认是push方式跳转,可定义replace方式)

navigate('/home?username=admin&password=123',{replace:true})

2、动态传参

(1)跳转时路径带参数

navigate('/home?username=admin&password=123',{replace:true})

(2)接收参数(useSearchParams())

import React from 'react'
import { useSearchParams } from 'react-router-dom'

export default function Home() {
	const [params] = useSearchParams()
    return (
		<div>
			<h3>主界面</h3>
            {params.get('username')} - {params.get('password')}
		</div>
	)
}

十三、定义组件局部css样式

1、定义局部样式原因:组件的全局样式会互相影响

2、定义方法

(1)css命名为index.module.css     //主要是要带module字段

(2)index.js中引入样式文件   import   styles  from  ’css文件路径‘

(3)使用(两种方式)

<p className={styles['user-msg']}></p>

//第二种方式:如果classname命名不带'-',就可以直接使用下面的方式
<p className={styles.gUser}></p>

十四、高阶组件(定义移动端TabBar)

1、定义首页、分类、购物车、我的和TabBar组件

2、定义首页、分类、购物车、我的路由(App.js中)

(1)注意:传子组件的方式:<Tabbar><Category/></Tabbar>


import {  BrowserRouter, Routes, Route,  Navigate } from 'react-router-dom'
import Home from './components/Home'
import Category from './components/Category'
import Cart from './components/Cart'
import My from './components/My'
import Tabbar from './components/Tabbar/Index'

function App() {
	return (
		<BrowserRouter>
			<Routes>
				<Route path="/" element={ <Navigate to="/home"/>}></Route>
				<Route path="/home" element={ <Tabbar><Home/></Tabbar>}></Route>
				<Route path="/category" element={ <Tabbar><Category/></Tabbar>}></Route>
				<Route path="/cart" element={ <Tabbar><Cart/></Tabbar>}></Route>
				<Route path="/my" element={ <Tabbar><My/></Tabbar>}></Route>
			</Routes>
		</BrowserRouter>
	)
}

export default App

3、TabBar组件内定义高阶组件

import React, { useState } from 'react'
import {NavLink} from 'react-router-dom'
import styles from './index.module.scss'
import '../../assets/iconfont/iconfont.css'

export default function Index({children}) {
	return <>{Tabbar(children)}</>

	/**
	 * 高阶组件
	 *   children
	 *
	 */
	function Tabbar(children) {
        const [id,setId] = useState(0) // 当前索引号
		const [list] = useState([
			{ path: '/home', title: '首页', icon: 'icon-daohanglan-03' },
			{ path: '/category', title: '分类', icon: 'icon-icon04' },
			{ path: '/cart', title: '购物车', icon: 'icon-shipin' },
			{ path: '/my', title: '我的', icon: 'icon-My' },
		])
		return (
			<div className={styles['g_home']}>
				<div className={styles.gMain}>
                    <div>{children}</div>
                </div>

				<div className={styles.gTabbar}>
                    <ul>
                        {list.map( (item,index)=>{
                            return (
                                <li>
                                    <NavLink to={item.path} className={index === id?styles.active:''}  onClick={()=>{ setId(index) }}>
                                        <span className={'iconfont '+item.icon}></span>
                                        <p  >{item.title}</p>
                                    </NavLink>
                                </li>
                            )
                        })}
                    </ul>
                </div>
			</div>
		)
	}
}

十五、Redux 状态管理

1、特点:

(1)集中式存储管理应用的所有组件的状态

(2)保证状态以一种可预测的方式发生变化

(3)简化Redux组件间通讯

2、核心概念与理论

(1)state: state对象包含所有数据。

(2) Store :  Store 就是保存数据的地方,你可以把它看成一个容器。整个应用只能有一个 Store。

(3) Action : Action 就是 View 发出的通知,表示 State 应该要发生变化了, Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置. 由组件store.dispatch(‘action’, payload)触发。

(4) Reducer: Store 收到 Action 以后,必须给出一个新的 State,这样 View 才会发生变化。这种 State 的计算过程就叫做 Reducer。(state,action)=> newState;

(5) dispatch:store操作行为触发方法,是执行action的方法。 store.dispatch(‘action’, payload)

(6)subscribe: Store 允许使用store.subscribe方法设置监听函数,一旦 State 发生变化,就自动执行这个函数。 只要把 View 的更新函数(对于 React 项目,就是组件的render方法或setState方法)放入listen,就会实现 View 的自动渲染。

(7) getState(): store.getState()获取state状态数据

3、安装

(1)npm install redux --save

4、基础使用

(1)新建store文件夹,文件夹下新建store,js文件

*注意:reducer中只能执行同步任务

import {createStore} from 'redux'
//状态对象
const initState={
    count:0
}

//reducer函数更新数据状态
const reducer=(state=initState,actions)=>{
      switch (actions.type) {
        case 'minus':
            return {...state,count:state.count+1}
        case 'plus':
            return{...state,count:state.count-1}
        default:
            return {...state}
      }
}

export const store=createStore(reducer)

(2)组件内引入暴露的store

 *获取值:store.getState().count

*改变值:store.dispatch({type:'minus'}  //dispatch中的对象是action对象

*注意:需要使用store.subscribe()去监听state内值的变化,然后使用useState()去更改值,从而刷新界面,与useEffect(()=>{ },[ ])配合使用,只启动一次监听器,就会永久监听

import React from 'react'
import { store } from '../store/store'
import {useState,useEffect} from 'react'
export default function Nba() {
  const [count,setCount] =useState(store.getState().count)
  useEffect(()=>{
    store.subscribe(()=>{
      let count=store.getState().count
      
      setCount(count)
    })
  },[])
  return (
    <div>
     <p>{count}</p> 
      <button type="button" onClick={()=>store.dispatch({type:'minus'})}>加一</button>
      <button type="button" onClick={()=>store.dispatch({type:'plus'})}>减一</button>
    </div>
  )
}

5、combineReducers(合并Reducers、适用于store.js里面有多个reducers时)

(1)使用:const reducer = combineReducers({counterReducer,cartReducer})

(2)组件中取值:let list = store.getState().cartReducer.list

6、vueX与reduX区别

(1)vuex中直接操作state状态数据是在mutations选项中,mutation中每个操作定义成一个方法;redux中直接操作state状态数据是在reducer中,只有一个函数,不同操作通过action动作的type区分

(2)reducer函数中操作state,先拷贝一份,更改之后返回一个新state

十五、Redux  Toolkit库(可以直接更改state内的值,不用拷贝一份再修改)

1、安装

npm i @reduxjs/tookit

2、使用

(1)store文件夹下定义xx.js文件内,使用导入的createSlice创建对象(state的名字必须是: initialState),内含接收参数的写法,获取组件传入的参数:action.payload

import { createSlice } from '@reduxjs/toolkit'

export const cartSlice = createSlice({
    name:'cart',
    initialState:{
        list:[{id:1001,name:'javascript',price:88.8}]
    },
    reducers:{
        addCart(state,action){
            let product = action.payload
            state.list.push(product)
        },
        deleteCart(state,action){
            let id = action.payload
            let index = state.list.findIndex(item=>item.id===id)
            state.list.splice(index,1)
        }
    }
})

export const {addCart, deleteCart} = cartSlice.actions
export default cartSlice.reducer

(2)store文件夹下定义的index.js文件内:集成多个reducers

import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './counterSlice'
import cartReduer from './cartSlice'

export default configureStore({
    reducer:{
        counter:counterReducer,
        cart:cartReduer
    }
})

(3)组件内使用

*注意:需要使用store.subscribe()去监听state内值的变化,然后使用useState()去更改值,从而刷新界面

//引入暴露的actions
import {addCart, deleteCart} from '../store/cartSlice'

//修改值
store.dispatch(addCart(product)) 

//获取值
store.getStore().counter.count

十六、React-Redux库(使用hooks函数简化组件内取值和改变值的操作)

1、安装

npm i react-redux

2、在index.js文件中导入Provider包裹App组件,还要导入暴露的store(让useSelector()与store建立联系,Provider透传store)

// 关联store
import { Provider } from 'react-redux'
import store from './store'

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

3、组件内导入useSelector,useDispatch

(1)注意:useSelector()会监听数据变化从而刷新界面,不用useState()更改值在刷新界面

(2)import { useSelector,useDispatch } from 'react-redux'

4、组件内使用

(1)获取值

const cartList= useSelector(state=>state.cart.list)

(2)修改值

const dispatch = useDispatch()

dispatch(addCart(product))

import {addCart, deleteCart} from '../store/cartSlice'
import { useSelector,useDispatch } from 'react-redux'

//获取值
const cartList= useSelector(state=>state.cart.list)

//修改值(含传参)
let product = {id:1002,name:'css编程',price:58.78}
const dispatch = useDispatch()
dispatch(addCart(product))

十七、Redux中进行异步任务操作(必须是在安装了Redux Toolkit库才行)

1、store文件夹下的xxx.js文件内

(1)引入createAsyncThunk(),创建对象,并暴露出去,在组件中使用(系统会自动封装成promise,返回三种状态:成功、加载、失败)

(2) extraReducers(builder){ }中获取异步任务返回的值,进行保存

import { createSlice,createAsyncThunk } from '@reduxjs/toolkit'

export const fetchBannerList = createAsyncThunk('banner/fetchList',async ()=>{
    // 调用banner接口获取bannerList
    let res = await axios({method:'get',url:'https://api.yuguoxy.com/api/shop/banner'})
    let {resultCode,resultInfo} = res.data
    if(resultCode === 1){
        let list = resultInfo.list
        return list
    }
    return []
    
})


export const bannerSlice = createSlice({
	name: 'banner',
	initialState: {
		bannerList: [],
	},
	reducers: {
		init(state) {}
	},
    extraReducers(builder){
        //成功处理fulfilled
        builder.addCase(fetchBannerList.fulfilled,(state,action)=>{
            //返回的数据 action.payload
            state.bannerList = action.payload
        })
    }
})

export default bannerSlice.reducer

2、组件中发起异步请求

(1)引入createAsyncThunk()所创建的暴露了的对象

(2)使用useDispatch进行传参(传入异步任务所返回的值)

	
import React from 'react'
import { useEffect } from 'react'
import  { useSelector,useDispatch} from 'react-redux'
import {fetchBannerList} from '../store/bannerSlice'

export default function Banner() {
    const bannerList = useSelector(state=>state.banner.bannerList)
    const dispatch = useDispatch()

    useEffect(()=>{
        dispatch(fetchBannerList())
    },[])

	return (
		<div>
			<h2>banner列表</h2>
			{bannerList.map(item=>{
                return (
                    <img src={item.url} alt={item.id} key={item.id} />
                )
            })}
		</div>
	)
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值