# React
# 1. React相关介绍
# 1. React特点
# A. 声明式设计
react是面向数据编程,不需要直接去控制dom,你只要把数据操作好,react自己会去帮你操作dom,可以节省很多操作dom的代码。这就是声明式开发。
# B. JSX语法
JSX 是 JavaScript 语法的扩展。React 开发大部分使用 JSX 语法(在JSX中可以将HTML于JS混写)。
# C. 灵活
react所控制的dom就是id为root的dom,页面上的其他dom元素你页可以使用jq等其他框架 。可以和其他库并存。
# D. 使用虚拟DOM、高效
虚拟DOM其实本质就是一个JavaScript对象,当数据和状态发生了变化,都会被自动高效的同步到虚拟DOM中,最后再将仅变化的部分同步到DOM中(不需要整个DOM树重新渲染)
# E. 组件化开发
通过 React 构建组件,使得代码更加容易得到复用和维护,能够很好的应用在大项目的开发中。
# F. 单向数据流
react是单向数据流,父组件传递给子组件的数据,子组件能够使用,但是不能直接通过this.props修改。 这样让数据清晰代码容易维护。
# 2. 环境搭建
# A . 全局安装脚手架(不推荐)
npm install create-react-app -g
# B. 通过npx搭建项目(官方推荐)
npx create-react-app 项目名
# 关于create-react-app
create-react-app
是FaceBook的React团队官方出的一个构建React单页面应用的脚手架工具,它本身集成了webpack
,并配置了一系列内置的loader
和默认的npm脚本,可以很轻松的实现零配置就可以快速开发React的应用# 关于npx
在 npm 的5.2.0版本开始,自动安装了npx
npx是什么? npx会帮助你执行依赖包里的二进制文件
npx会自动查找当前依赖包中的可执行文件,如果找不到,就会去PATH里找。如果依然找不到,就会帮你安装
该命令建议运行在node的12.13.0版本的基础上
# C. 清除项目中的默认文件
删除掉新项目中 src/
文件夹下的所有文件
# 1.进入到src目录下
cd 项目名/src
# 2.删除src目录下的所有文件
# 如果你使用 Mac 或 Linux:
rm -f *
# 如果你使用 Windows:
del *
# 3.新建一个index.js文件
touch index.js
# 4.然后回到项目文件夹
cd ..
# 5.复制一下代码到index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from "./App"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
);
# 6.运行项目
npm start
# D. 书写第一个组件
import React from 'react'
class App extends React.Component{
render(){
return (
<div>我的第一个组件</div>
)
}
}
export default App
# E. VSCode中JSX的编写优化
# 2. 组件化开发
# 定义组件
定义组件分为3步:
导入React核心模块
定义组件类
导出组件
在src目录下新建App.js文件:
//1、导入React核心模块
import React from 'react'
//2、定义组件类
class Hello extends React.Component{ //类
render(){ //函数
return ( //返回值
<div>
hello world !!! 我是组件
</div>
)
}
}
//3、导出组件
export default Hello
/*
为什么继承Component?
因为继承Component,组件里就可以写render,return(标签),然后React就会帮助渲染成浏览器认识的标签
*/
# 引入组件
在需要引入该组件的index.js中,导入,就可以直接使用这个组件了:
//import 组件名 from '文件路径'
//1、导入Hello组件 (首字母必须大写)
import Hello from './App'
ReactDOM.render(
// 2、使用Hello组件 (首字母必须大写)
<Hello />
, document.getElementById('root'));
//注意:Hello是组件名,在使用的时候就应该写JSX标签写法,而不能直接写Hello
# 注意:
定义组件的时候,return 后面只能有一个根标签,不能有多个,但这个标签内部可以有其他多个标签
使用组件的时候,首字母必须大写,(是为了和标签进行区分,标签是小写)
如果最外层实在不想放置一层div根目录,可以使用
<></>
空标签代替写jsx要套在
return ()
里,写js语法要套在{}
里
# 3. jsx语法糖
React使用JSX来替代常规的javascript。jsx是一个看起来很像XML的JavaScript语法扩展,在React中会被babel编译为JavaScript。
语法糖:一个功能,有两种完成方式,其中简单的写法。叫语法糖
Babel 是一个 JavaScript 编译器
# a. JSX的特点
1. jsx执行更快,因为它在编译为JavaScript代码后进行了优化
2. 它是类型安全的,在编译过程中就能发现错误
3. 使用jsx编写模版更加简单快速
# b. JSX几个注意的格式
- React的JSX是使用大写和小写字母来区分本地组件和HTML标签
- JSX和HTML的标签属性的区别
HTML标签属性 | JSX | 原因 |
---|---|---|
for | htmlFor | for在js中为for循环的关键字 |
class | className | class在js中为声明类关键字 |
style | 需使用JS对象(使用双花括号--{{}} ) |
# c. jsx 和 html 区别
- 行内样式 必须是一个对象 第一个{}代表js环境 第二个 {} 代表 对象格式
<div style="{{width:"200px"}}"></div>
jsx中不要使用class,用className代替
在jsx中使用js代码,必须要写在{}
jsx 本地图片先引入 后使用
其他的,都可以当做HTML语法来用
# d. 文件引入方式
//引入后立即执行
import "./Index.css"
//什么时候调用什么时候执行
import Img from "../static/logo.png"
# e. JSX是React虚拟出来的DOM对象
// js创建DOM元素
document.createElement("div")
// React的标签对象
React.createElement("div",{className:"box"},"hello")
# 4. 类式组件
import {Component} from 'react'
export default class App extends Component{
// constructor 专门用来初始化
constructor(props){
super(props)
// 定义组件内部数据
this.state = {
num:20
}
}
render(){
return (
{/* 在JSX上获取组件内部数据 需要通过 this.state.变量名 */}
<div>{this.state.num}</div>
<button onClick={this.handleClick.bind(this)}>按钮</button>
)
}
handleClick(){
// 需要修改到组件内部数据,需要用到this.setState方法来修改
// 在函数中,如果需要使用this,就得在调用的时候传递this
// this.setState() 这个方法是异步的
// this.setState() 提供的第二个参数是一个回调函数,修改了数据之后才执行
this.setState({
num:this.state.num+1
},()=>{
// 修改数据之后才执行
console.log(this.state.num)
})
}
}
# super的作用究竟是什么?
super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
# super()加与不加props的区别究竟在哪里呢?
这是因为 react 在初始化 class 后,会将 props 自动设置到 this 中,所以在任何地方都可以直接访问 this.props,除了一个地方:
constructor
;所以如果你需要在构造函数内使用this.props,就需要传递props作为super()的参数。
# a. 插值语法
import React, { Component } from "react";
export default class App3 extends Component {
state = {
name: "苏东旭",
num: 10,
};
render() {
return (
<div>
<p>{this.state.name}</p>
<p>{this.state.num}</p>
</div>
);
}
}
# b. 事件的三种写法
this.事件名.bind(this,传递的参数)
import {Component} from 'react'
export default class App extends Component{
constructor(props){
super(props)
this.state = {
title:"我是标题"
}
this.handleClick = this.handleClick.bind(this)
}
render(){
return (
<>
<button onClick = {this.handleClick.bind(this)}>按钮1</button>
<button onClick = {this.handleClick}>按钮2</button>
<button onClick = {()=>this.handleClick()}>按钮3</button>
</>
)
}
handleClick(){
this.setState({
title:"修改后的标题"
})
}
}
# c. 双向数据绑定
react不会问react双向绑定原理的,没有双向绑定
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
val: "默认值",
};
}
inp(e) {
this.setState({
val: e.target.value,
});
}
render() {
return (
<div>
<input
type="text"
value={this.state.val}
onChange={this.inp.bind(this)}
/>
<p>{this.state.val}</p>
</div>
);
}
}
# d. 循环
react只支持map遍历
import {Component} from 'react'
export default class App extends Component{
constructor(props){
super(props)
this.state = {
arr:['html','css','js','jq','node','ts','vue','react']
}
}
render(){
return (
<>
<ul>
{
this.state.arr.map((item,index)=>{
return (
<li key={index}>{item}</li>
)
})
}
</ul>
</>
)
}
}
# e. 数组操作
- 普通写法
import React from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: ["html", "css", "js", "jq", "vue"],
};
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>添加</button>
<ul>
{this.state.arr.map((item, index) => {
return <li key={item}>{item}</li>;
})}
</ul>
</div>
);
}
handleClick() {
this.setState({
// 浅拷贝
arr: [...this.state.arr, "react"],
});
}
}
- 深拷贝写法
import React from "react";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
arr: ["html", "css", "js", "jq", "vue"],
};
}
render() {
return (
<div>
<button onClick={this.handleClick.bind(this)}>添加</button>
<ul>
{this.state.arr.map((item, index) => {
return <li key={item}>{item}</li>;
})}
</ul>
</div>
);
}
handleClick() {
// 深拷贝
let newArr = JSON.parse(JSON.stringify(this.state.arr));
newArr.push("react");
this.setState({
arr: newArr,
});
}
}
# f. 父子传值
# 1. 父传子
在父组件的子组件标签中设置自定义属性,并将要传递的数据作为其属性值
在子组件中直接通过
this.props.自定义属性
获取父组件传递的数据
# 父组件传值
在父组件中引入子组件
// 组件名首字母一定大写 import 子组件名 from "子组件位置"
直接用就行,无需注册
render(){ return( <div> <子组件 自定义属性={父组件数据}></子组件> </div> ) }
# 子组件接值
<p>{this.props.自定义属性名}</p>
子组件中限制默认值
static defaultProps = { 自定义属性名:"属性值", title:"默认值" }
子组件中限制类型
// 引入限制类型的模块 import PropTypes from "prop-types" // 限制类型 注意不能直接写类型,需要单独引入 限制类型 的模块 static propTypes = { 自定义属性名:PropTypes.String }
# 2. 子传父
# 子组件传值
在子组件中为某元素添加点击事件,并将事件触发的方法进行声明,在方法内通过
this.props.自定义事件(传递数据)
在父组件的子组件标签中使用该自定义事件,不加on,自定义事件触发的方法在父组件中进行声明,方法的形参就是子组件传递过来的数据
需要一个契机,为元素添加点击事件
<button onClick={this.子组件方法.bind(this)}>子组件按钮</button>
声明点击事件的方法,并通过
this.props.自定义事件(传参)
子组件方法(v){ this.props.自定义事件("传递的数据") }
# 父组件接值
子组件标签内,使用自定事件,不加on
<子组件 自定义事件={this.父组件方法.bind(this)}></子组件>
父组件中声明子组件自定义事件触发的方法
父组件方法(v){ //形参v就是子组件传递的数据 }
# g. 组件跨级值传递Context
React组件之间的通信是基于props的数据传递,数据需要一级一级从上到下传递。如果组件级别过多传递就会过于麻烦。React中 Context
配置可以解决组件跨级值通信
适合获取数据,如果修改的话,还是建议放在redux中
# 方式一
# 向下传递
import React,{Component} from 'react'
import PropTypes from 'prop-types'
// 爷爷
export default class Comp1 extends Component{
// 声明要传递的数据类型
static childContextTypes = {
fnum:PropTypes.number
}
// 保存要传递的数据到上下文环境中
getChildContext(){
return {
fnum:40
}
}
render(){
return (
<Child></Child>
)
}
}
// 爸爸
class Child extends Component {
render(){
return (
<div>
<ChildChild></ChildChild>
</div>
)
}
}
// 孙子
class ChildChild extends Component {
// 在哪个组件中想要获取fnum这个数据,就必须写两个东西
// 1. 接收的类型
static contextTypes = {
fnum:PropTypes.number
}
render(){
return (
<div>
孙子组件
{/* 2. 通过this.context.fnum获取值 */}
{this.context.fnum}
</div>
)
}
}
# 方式二
配置createContext
// ctx.js 哪个组件使用就引入
import {createContext} from "react"
const ctx = createContext()
export default ctx
/*
ctx有两个组件(标签)
Provider 发送数据
Consumer 接收数据
*/
# 向下传递
父辈通过Provider的value属性向下传递数据
后代通过
(value)=>{}
接收数据
import React, { Component } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
render() {
return (
<Provider value={{ name: "苏东旭" }}>
<Child></Child>
</Provider>
);
}
}
// 爸爸
class Child extends Component {
render() {
return <ChildChild></ChildChild>;
}
}
// 孙子
class ChildChild extends Component {
render() {
return (
<Consumer>
{(value) => {
return <h2>{value.name}</h2>;
}}
</Consumer>
);
}
}
# 向上传递
父辈传参时传一个函数,并声明一下该函数,函数的形参就是将来后代传递过来的数据
后代在函数的形参处传值
import React, { Component } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
render() {
return (
<Provider value={{ name: "苏东旭", fn: this.data.bind(this) }}>
<Child></Child>
</Provider>
);
}
data(v) {
console.log(v);
}
}
// 爸爸
class Child extends Component {
render() {
return <ChildChild></ChildChild>;
}
}
// 孙子
class ChildChild extends Component {
render() {
return (
<Consumer>
{(value) => {
return (
<div>
<h2>{value.name}</h2>
<button onClick={value.fn("孙子向上传递的数据")}>传递</button>
</div>
);
}}
</Consumer>
);
}
}
# h. 组件的生命周期
类的生命周期分为三个大阶段:挂载、更新、卸载
每个大阶段又有若干小阶段,其中在整个生命周期中render会被执行两次(挂载和更新阶段各执行一次)
# 挂载阶段
#
constructor
: 当对象刚刚类创建出来的时候#
componentWillMount
: 组件即将渲染【没用,现在已经废弃了】#
render
: 组件正在渲染#
componentDidMount
: 组件渲染完毕
// 当对象刚刚类创建出来的时候
constructor(){
super()
console.log("生命周期的第一个阶段---刚刚创建出来")
//作用:就是为了初始化state的数据
}
// 组件即将渲染【没用,现在已经废弃了】
UNSAFE_componentWillMount(){
console.log("生命周期的第二个阶段---组件即将渲染")
}
// 组件正在渲染
render(){
console.log("生命周期的第三个阶段---组件正在渲染")
}
// 组件渲染完毕
componentDidMount(){
// react官方要求,推荐在componentDidMount中请求数据
console.log("生命周期的第四个阶段---组件渲染完毕")
}
# 更新阶段
#
shouldComponentUpdate
: 应该更新么,返回true或false#
componentWillUpdate
: 即将更新【已废弃】#
render
: 正在更新#
componentDidUpdate
: 更新完毕
# state更新
import React, { Component } from "react";
export default class Child extends Component {
constructor() {
super();
this.state = {
num: 1,
};
}
dian() {
this.setState({
num: "苏东旭",
});
}
// 在这个方法中,判断数据修改前后是否一致,不一致才去render,减少不必要的更新,优化更新性能
shouldComponentUpdate(nextProps, nextState) {
console.log("修改的第一阶段:可以修改么");
if (this.state.num === nextState.num) {
return false;
} else {
return true;
}
}
UNSAFE_componentWillUpdate() {
console.log("修改的第二阶段:即将修改【已废弃】");
}
render() {
console.log("修改的第三阶段:正在修改");
return (
<div>
Child
<p>{this.state.num}</p>
<button onClick={this.dian.bind(this)}>按钮</button>
</div>
);
}
componentDidUpdate() {
console.log("修改的第四阶段:修改完毕");
}
}
# props改变
componentWillReceiveProps(){
// props数据的变化,才会触发这个方法的执行
}
# 卸载阶段
#
componentWillUnmount
: 主要用于释放数据、清空缓存
componentWillUnmount() {
// 释放数据 清空缓存
console.log("被销毁了");
}
# 总结:
#
componentDidMount
适合做数据请求#
shouldComponentUpdate
优化更新性能
# 5. 函数式组件
react里面组件分两种
类式组件
函数式组件
- 没有state,但是提供了很多的hook函数,数据渲染简洁
- 没有this,它指向window
- 没有生命周期函数(靠 hook 模拟出来)
- 写的都是js原生,数据不是响应式的
// 这就是一个简单的函数式组件
import React from 'react'
export default function App() {
return (
<div>Demo</div>
)
}
# useState 响应式数据
# 使用:
let [变量名,修改变量的回调] = useState(默认值)
# 修改:
修改变量的回调(变量名)
import React,{useState} from "react"
export default function App() {
// 第一个数据 就是我们想要使用的组件内部数据
// 第二个数据 是专门用来修改第一个数据的方法名 setNum(新值) 表示把第一个数据改成新值
// 第三个数据 useState方法的形参就是第一个数据的初始值
const [num,setNum] = useState(0)
function hdClick(){
setNum(num + 1)
}
return (
<div>
<p>{num}</p>
<button onClick={hdClick}>按钮1</button>
<button onClick={() => setNum(num + 1)}>按钮2</button>
</div>
)
}
# 父子组件传值
# 父传子
给儿子自定义属性
儿子在函数参数位置接取props
import React,{useState} from 'react'
function Child(props){
let {num} = props
return (
<div>
<h2>{num}</h2>
</div>
)
}
export default function Father(){
const [num,setNum] = useState(10)
return (
<div>
<Child num={num}></Child>
</div>
)
}
# 子传父
给儿子传函数
儿子调用函数传值
import React, { useState } from "react";
function Child(props) {
let { num, changeNum } = props;
return (
<div>
<h2>{num}</h2>
<button onClick={changeNum}>按钮</button>
</div>
);
}
export default function Father() {
const [num, setNum] = useState(10);
return (
<div>
<Child num={num} changeNum={() => setNum(num + 1)}></Child>
</div>
);
}
# Hook 多级组件传值
ctx.js
import {createContext} from "react"
const ctx = createContext()
export default ctx
父辈组件
import React from "react";
import Baba from "./Baba";
import ctx from "./ctx";
let { Provider } = ctx;
export default function Yeye() {
const jie = (v) => {
console.log(v);
};
return (
<Provider value={{ name: "苏东旭", fn: jie }}>
<div>
yeye
<hr />
<Baba />
</div>
</Provider>
);
}
中间
import React from "react";
import Son from "./Son";
export default function Baba() {
return (
<div>
Baba
<hr />
<Son></Son>
<Sunzi />
</div>
);
}
后代组件
import React from "react";
import { useContext } from "react";
import ctx from "./ctx";
export default function Son() {
const value = useContext(ctx);
return (
<div>
Son
<p>{value.name}</p>
<button
onClick={() => {
value.fn("苏东旭");
}}
>
契机
</button>
</div>
);
}
# Hook模拟生命周期
componentDidMount 请求数据 组件渲染完毕
componentDidUpdate 数据更新完毕
componentWillUnmount 页面关闭的时候
useEffect(回调函数,数组)
- 第二个参数是空数组 [] ,不监听任何一个数据的变化 代替 componentDidMount
- 第二个参数不写,监听所有内容,代替componentDidUpdate
- 第二个参数 非空数组[有内容] 只监听 [] 里面的数据的改变 类似watch,不代替任何一个生命周期
- 如果里面有return 函数,代表页面关闭的时候执行 代替componentWillUnmount
useEffect做请求数据,一定是空数组
里面不支持async/await
# Hook获取DOM元素
useRef 获取DOM元素
import React from "react";
import { useRef } from "react";
export default function App6() {
const inp = useRef();
const box = useRef();
const dian = () => {
console.log(inp.current.value);
console.log(box.current);
};
return (
<div>
App6
<input type="text" ref={inp} />
<div ref={box}>盒子</div>
<button onClick={dian}>获取dom</button>
</div>
);
}
# Hook 计算属性
useMemo(回调函数,[监听的内容])
import React from "react";
import { useMemo } from "react";
import { useState } from "react";
export default function App7() {
const [num, setNum] = useState(10);
let total = useMemo(() => {
return num * 2;
}, [num]);
return (
<div>
<p>{num}</p>
<p>{total}</p>
<button
onClick={() => {
setNum(num + 1);
}}
>
按钮
</button>
</div>
);
}
# 6. 路由
# 路由切换原理
<html lang="en">
<head>
<title>路由切换原理</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
</head>
<body>
<ul>
<li><a href="#/login">点击跳转登录页</a></li>
<li><a href="#/reg">点击跳转注册页</a></li>
</ul>
<div id="routerview"></div>
<script>
// 路由表
let routes = {
"#/login":"./login.html",
"#/reg":"./reg.html"
}
// 当路由发生变化时 hashchange事件,重新加载 routes中的视图
window.addEventListener("hashchange",()=>{
$("#routerview").load(routes[location.hash])
})
</script>
</body>
</html>
# 安装路由
npm install react-router-dom@6
- 在 src/router/index.jsx
// 先安装路由 npm i react-router-dom@6
// 这不仅仅是一个路由文件,它也是一个路由组件
// BrowserRouter是一个路由组件(自带的history模式),同时还有一个HashRouter(自带hash模式)
// 引入三个路由组件
import { BrowserRouter, Routes, Route } from "react-router-dom";
// BrowserRouter 指定路由模式 HashRouter 两种路由模式
// Routes 路由表
// Route 路由
// 1. 引入要跳转的组件
import Home from "../views/router/Home";
import User from "../views/router/User";
// 2. 创建路由
const router = (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />}></Route>
<Route path="/user" element={<User />}></Route>
</Routes>
</BrowserRouter>
);
export default router;
# 子路由
# 配置子路由
Route嵌套Route
<Route>
<Route></Route>
</Route>
# 子路由页面展示
import {Outlet} from 'react-router-dom';
<Outlet></Outlet>
# 路由跳转
# Link方式
import {Link} from "react-router-dom";
<Link to="/路径">标题</link>
# JS方式
import {useNavagate} from "react-router-dom"
let navigate = useNavigate()
const goHome=()=>{
navigate("/Home")
}
<button onClick={goHome}>首页</button>
# 路由传参
# 1. 动态路由
优点:美观,但是需要修改路由配置文件
# 传参
- 配置文件
<Route path="/路由规则/:id/:name/xxxxx"></Route>
- 路由传参
// Link方式
<Link to="/路由规则/参数1/参数2/...">首页</Link>
// JS方式
import {useNavagate} from "react-router-dom"
let navigate = useNavigate()
const goHome=()=>{
navigate("/路由规则/参数1/参数2/...")
}
<button onClick={goHome}>首页</button>
# 接参
Hook
import (useParams) from "react-router-dom"
let params = useParams()
console.log(params)
# 2. 通过查询字符串
# 传参
//?id=19&name=苏东旭
// Link方式
<Link to="/路由规则?参数1=xxx&参数2=xxx...">首页</Link>
// JS方式
import {useNavagate} from "react-router-dom"
let navigate = useNavigate()
const goHome=()=>{
navigate("/路由规则?参数1=xxx&参数2=xxx...")
}
<button onClick={goHome}>首页</button>
# 接参
Hook
import {useSearchParams} from "react-router-dom"
const [data] = useSearchParams()
console.log(data.get('参数1'))
# 3. 通过navigate函数传参
# 传参
添加第二个参数 {state:{}}
import {useNavigate} from "react-router-dom"
let navigate = useNavigate()
const goHome=()=>{
navigate("/路由规则",{
state:{
id:17,
name:"小星星"
}
})
}
<button onClick={goHome}>首页</button>
# 接参
import (useLocation) from "react-router-dom"
let location = useLocation()
console.log(location.state)
总结
传参 useNavigate
接参 useLocation
# 7. Redux状态管理
# 安装
npm i redux react-redux
# 使用redux
redux只有两种属性
- 数据(自定义起名:baseState)
- 修改(自定义起名:reducer)
# 定义
import {createStore} from "redux"
// 初始值
const baseState = {
const:10,
name:"张三"
}
// 设置数据和修改 state初始数据 action修改方法
const reducer = (state=baseState,action)=>{
// 必须先深拷贝
let nstate = JSON.parse(JSON.stringify(state))
//============================
【把修改的方法写这里】
console.log(action)
if(action.type === 'type值'){
//业务逻辑
}else if(action.type === 'type值'){
//业务逻辑
}
//============================
return nstate
}
// 创建仓库
const store = createStore(reducer)
// 开放出去
export default store
# 传值
//引入仓库
import store from "../../store"
//引入发送数据的组件
import {Provider} from "react-redux";
//希望哪些后代能共用 redux的值就可以使用Provider进行包裹
<Provider store={store}>
</Provider>
# 接取
import {useSelector} from 'react-redux'
const data = useSelector(state=>state)
console.log(data.键)
# 修改
import {useDispatch} from 'react-redux';
const dispatch = useDispatch()
const fn = () =>{
// dispatch() 可以直接调用 store/index.js的reducer方法
dispatch({
type:"", //必须有type,其他的随意
//数据直接发给reducer的action
})
}
<button onClick={fn}></button>
总结
传值 Provider
接值 useSelector
修改 useDispatch