初识 react
- 导入react文件
<!-- react 核心文件 暴露一个 React 对象 -->
<script src="./js/react.development.js"></script>
<!-- react 操作dom 的文件 暴露一个 ReactDOM 对象 -->
<script src="./js/react-dom.development.js"></script>
- 创建容器
<div id="root"></div>
- 创建 react 元素
let vdom = React.createElement("h1",{title:"初识react"},"hello world!");
- 将创建好的react元素展示到 容器中
ReactDOM.render(vdom,document.getElementById("root"));
createElement 参数
第一个 参数 标签名 第二个参数 标签的属性 {title:"初识 react"} / null 从第三个参数开始 全部都是 标签体的内容
dom
真实dom 直接在html文件中写好的。
虚拟dom 通过 React.createElememt() 所创建的
区别: 虚拟dom比较轻。属性比较少。
jsx
在 js 中 更高效的写html标签 浏览器不会识别 jsx 语法。 babel 可以将 jsx 语法 转换为 js 语法。
JSX 注意
1. 不能用引号包裹,可以用 (小括号) 包裹
2. JSX 与 js 拼接时,需使用 {} 表达式
3. JSX 设置 class 时,须使用 className
4. JSX 设置 style 时,须使用 {{color:"red",textAlign:"center",fontSize:"30px"}} 形式, css样式 多单词 须使用 小驼峰形式
5. JSX 必须要有根标签
6. JSX 中的单标签必须闭合, 例: <img/> <hr/> <br/> <input/> 等,或者<img><img/>形式
7. JSX 中的标签名
(1) 小写字母开头,则到HTML中找对应的标签,找到则创建,找不到则报错;
(2) 大写字母开头,则到React中找对用的组件,找到则创建,找不到则报错;
(3) 如果编写的html标签,则标签名首字母[一定要小写];如果编写的时React组件,则标签名首字母[一定要大写]
jsx 中的表达式
- 字面量数据 string number array function 有意义 boolean undefined null Symbol 没有意义 object 会报错
- 变量
- 方法调用
- 逻辑运算符 &&
- react 元素虚拟dom对象
jsx 条件渲染
- if else
- 三元运算符
- 逻辑运算符 &&
js中的循环
- for 已知条件,已知范围
- while 未知条件,未知范围
- do while 至少执行一次
- for of 循环遍历数据
- for in 循环遍历对象
- forEach 循环遍历数组,数组一个方法
- map 循环遍历数组,数组一个方法,返回一个新数组
diff 算法 以及 key
diffing react内置的算法:高效的 更新虚拟dom key 为虚拟dom添加唯一标识符 id 时间戳
js 事件
js是一个事件驱动的语言
事件必须调用函数
事件:
onclick
onmouseover
onmouseout
onchange
onblur
onfocus
keyUp
keyDown
为元素绑定事件
1.
document.getElementById("btn").onclick = function(){
}
2.
document.getElementById("btn").addEventListener("click",function(){
})
3.
<button id="btn" onclick="alert(123)">点击</button>
react中的事件
- react中的事件 必须使用小驼峰
- 事件必须调用函数
- 事件中的this 指向 undefined
- 阻止默认行为只能用 e.preventDefault();
- onChange事件 文本框值发生变化立即触发
默认行为
- 点击 a 链接会跳转
- 点击 submit 按钮会提交表单
- 鼠标右键 会显示菜单
- ctrl+c 复制
组件
传统封装 : js 函数 类 模块化 组件: html + css + js 封装 组件本质:就是自定义标签
react 中的组件
-
函数式组件 (1) 组件名称 必须首字母大写,返回虚拟dom (2) 组件以标签的形式在使用 (3) 组件名称见名知义 (4) 使用组件, 会在当前页面中去找 对应的这个 函数 ,调用执行函数,然后返回虚拟dom对象
-
类式组件 (1) 组件名称 必须首字母大写,返回虚拟dom (2) 组件以标签的形式在使用 (3) 组件名称见名知义 (4) 使用组件, 会在当前页面中去找 对应的这个 类,然后自动实例化对象,会自动调用render方法 ,然后返回虚拟dom对象
如何改变this指向
- call
- bind
- apply
- new 关键字: 创建了一个 空对象,并将this指向到这个对象
js 默认继承
原型继承 构造函数 类
nrm
- 安装 nrm 管理 npm 的资源的下载地址 npm i -g nrm
- 查看所有的npm 的下载的资源地址 nrm ls
- 配置 npm 镜像 nrm use taobao
安装react脚手架环境
- 下载安装环境 npm i create-react-app -g
- 创建项目 create-react-app 项目名(不能写汉字,不能有大写)
- 进入项目目录 cd hello-react
- 启动项目 npm start
git
将 项目 git 管理起来
- git init 初始化
- git add . 提交全部文件到 缓存区
- git commit -m "项目初始化"
vscode安装 git 可视化插件
Git Graph
react 脚手架目录结构
node_modules 依赖包目录
public 静态资源文件(网站根目录)
index.html webpack最终打包的模板文件
src 源代码目录
index.js 项目的入口文件
.gitignore git忽略文件
package.json 项目的说明配置文件
package-lock.json 项目依赖包的锁文件
图片
- 位图 jpg png gif 图片内容比较丰富,缩放会失真。
- 矢量图 svg 图片内容比较单调,缩放不会失真。网站logo,导航图标
react 版本
目前: 最新版 18.2.0 react 最重要的版本 16.8, 16.8 之前官方推荐我们使用 类式组件 16.8 之后官方推荐我们使用 函数式组件 + hooks
安装 17:npm i react@17 react-dom@17
App 根组件
作用: 用来展示所有的组件
react 中的样式
外部样式 都是全局样式
- 解决样式作用域: less scss sass
组件三大属性之一 state
state 状态 存储数据 state 值 一般为js对象
state 中存储哪些数据:
- 后台传递的数据
- 前台通过表单收集到的用户的数据
组件中的 虚拟DOM 中的this 指向 当前的组件对象(实例对象)
react 中的事件回调里 的 this 指向 undefined
state 中的数据不能直接去更新 必须使用 this.setState() 更新 state中的数据。
vscode 插件
- Reactjs code snippets 快捷键: rcc 创建类式组件
- Auto Rename Tag
- Auto Close Tag
render 执行了几次?
render 渲染 将虚拟dom转换为真实dom 1 + n 次
组件
- components 一般(功能)组件
- pages 页面(路由)组件
组件数据
数据在哪,就只能在对应的组件中去更新数据
类式组件的三大属性之一 props
作用:接受父组件传递的数据 特点:
-
props 数据是只读的,不能修改
//在父组件中传递数据
<Middle>{this.state.middleArr}</Middle>
//在子组件中接受数据
this.props.children
//缺点:每次只能传递一个数据
//children 存放组件标签体中的内容
//在父组件中传递数据
<Middle middleArr={this.state.middleArr} str={this.state.str} num={this.state.num} showPosition={this.showPosition}></Middle>
<Middle {...this.state}></Middle>
//在子组件中接受数据
let {middleArr,str,num} = this.props
//优点: 传递数据的个数不限
props 数据验证
-
导入 props-types 包 import PropsType from "props-types"
-
在类中 创建 静态属性
//数据类型: string、boolean、number、object、array、func还有element(react元素)
static propTypes = {
middleArr:PropsType.array.isRequired,
str:PropsType.string.isRequired,
num:PropsType.number.isRequired,
showPosition:PropsType.func.isRequired
}
//指定默认数据
static defaultProps = {
str:"默认数据"
}
组件(实例对象)三大属性
- state 状态 存储组件中的所有数据:后台传递的,前端表单收集的。
- props 接受外部组件传递的数据(字面量数据、方法)
- ref 获取真实 DOM 对象
组件的三大属性之一 ref
作用: 获取真实 DOM 对象
- 字符串形式 ref
<div> <h1> 字符串形式的 ref </h1> <input type="text" ref="username" /> <button ref="btn" onClick={this.getdata} >点击获取数据</button> <div ref="div" style={{width:300,height:300,border:"1px solid red"}}></div> </div> //获取数据 getdata = ()=>{ console.dir(this.refs.username.value); //获取输入框值 let value = this.refs.username.value; //设置div内容 this.refs.div.innerHTML = value; //清空输入框内容值 this.refs.username.value = ""; }
2. 回调函数形式的ref
``` jsx
<h1> 回调函数形式的 ref </h1>
{/* react 执行时,会将 当前的真实dom对象作为参数 执行 回调函数 */}
<input type="text" ref={ (el)=>{this.username = el} } />
<button onClick={this.getdata} >点击获取数据</button>
<div ref={ el => this.div = el } style={{width:300,height:300,border:"1px solid red"}}></div>
//获取数据
getdata = ()=>{
// console.log(this);
//获取输入框值
let value = this.username.value;
//设置值
this.div.innerHTML = value;
//清空数据
this.username.value = "";
}
- 使用 createRef() 创建 ref 容器
// 1. 使用 React.createRef() 创建ref容器,将ref容器注册到当前的实例对象属性
username = React.createRef();
div = React.createRef();
{/* 2.使用 ref容器 */}
<input type="text" ref={this.username} />
<button onClick={this.getdata} >点击获取数据</button>
<div ref={this.div} style={{width:300,height:300,border:"1px solid red"}}></div>
//获取数据
getdata = ()=>{
console.log(this.username.current.value);
//获取数据
let value = this.username.current.value;
//设置数据
this.div.current.innerHTML = value;
//清空数据
this.username.current.value = "";
}
vscode 插件
Template String Converter
非受控组件
表单中的的数据通过 ref 形式获取到,并没有被state所管理。
受控组件
表单中的的数据 被 state 所管理。
高阶函数
- 构造函数
- 工厂函数
特点: 其实就是一个函数,接受一些函数类型的参数 或者 返回一个函数
- 接受函数类型的参数: Promise then catch setTimeout setInterval 数组一些方法(map forEach filter every )
- 返回一个函数 : 闭包 bind
html input type
html4: text password radio checkbox button submit reset image html5: url email number range search date week time datetime-local color tel
组件的生命周期
概念: 组件从创建 到 销毁的一系列过程 就叫组件的生命周期 在这个过程中,会自动调用一些函数,这些函数 就叫生命周期钩子函数
-
componentDidMount 组件完成渲染【挂载】时调用 做组件初始化的工作 创建定时器 发送ajax请求 订阅消息 操作 DOM
-
componentDidUpdate 组件完成更新时调用 操作 DOM
-
componentWillUnmount 组件将要卸载时调用 做组件收尾的工作 销毁定时器 取消订阅
-
render 渲染虚拟DOM 执行次数 1 + n
moment 获取日期库
- 下载安装 npm install moment --save --force
- 导入使用 import moment from "moment"
- 使用 moment().format("YYYY-MM-DD HH:mm:ss");
函数式组件 + hooks
hook 本质就是函数 rfc 快速创建函数式组件
注意:
- 只在最顶层使用 Hook,不要在条件或循环中
- 只在React组件函数内部中调用 Hook, 不要在组件函数外部调用
useState
作用:在函数式组件中创建状态
vscode react 插件
ES7+ React/Redux/React-Native snippets rfc 快速创建 函数式组件
useRef
作用: 获取真实DOM对象
useEffect
作用: 在函数式组件中模拟 生命周期钩子函数
//1. 相当于 模拟 componentDidMount 和 componentDidUpdate
useEffect(()=>{
console.log("相当于 模拟 componentDidMount 和 componentDidUpdate");
});
// 2. useEffect 可以多次使用 模拟 componentDidMount 和 componentDidUpdate
useEffect(()=>{
console.log("执行了多次");
})
// 3. 单独模拟 componentDidMount
useEffect(()=>{
console.log("单独模拟 componentDidMount ");
},[]);
//监听某个状态的变化,然后执行componentDidUpdate
useEffect(()=>{
console.log("单独模拟 componentDidMount ");
},[count]); // [] 可以写状态,作用:监听哪个状态发生变化,然后执行componentDidUpdate
// 4. 模拟 componentWillUnmount
useEffect(()=>{
return ()=>{
console.log("模拟 componentWillUnmount");
}
},[]);
组件三大属性
- 类式组件 state 存储状态 props 获取外部组件传递的数据 ref 获取真实DOM对象
- 函数式组件 useState 存储状态 useRef 获取真实DOM对象 props 获取外部组件传递的数据
todolist
- 创建及 分拆组件
- 分析数据 状态的存储位置 todolist
- 状态 [ {id:1,title:"事件名称",done:false}, {id:2,title:"事件名称",done:false}, {id:3,title:"事件名称",done:false}, {id:4,title:"事件名称",done:false}, {id:5,title:"事件名称",done:false} ]
todolist 列表展示
- 在todolist 组件中创建 状态 数据
- 在 todolist 传递数据
<TodoMain todolist={todolist} />
- 在 TodoMain 通过 props 接受外部组件传递的数据
//解构赋值 获取props 数据
let {todolist} = props;
return (
<ul className="todo-main">
{
todolist.map(item=>{
return <TodoItem item={item} key={item.id}></TodoItem>
})
}
</ul>
)
}
- 在 TodoItem 通过 props 接受外部组件传递的数据
//解构赋值获取item
let {item} = props;
return (
<li>
<label>
<input type="checkbox" checked={item.done} />
<span>{item.title}</span>
</label>
<button className="btn btn-danger" style={{display:"none"}}>删除</button>
</li>
)
todolist 新增一个数据
- 在 todoHeader 将 input 绑定value值,并且绑定 onChange事件。作为一个 受控组件
- 在 todoHeader 为 input 绑定 onKeyUp 事件,获取 用户的 回车键。
- 在 todolist 组件中创建 addTodo 方法,为 state中的todolist数据 添加一个新的数据
- 在 todolist 组件中 使用 useEffect 测试 addTodo 方法
- 在 todolist 组件中 将 addTodo 方法传递给 todoHeader 组件
- 在 todoHeader 通过 props 接受 方法
- 在 keyup 中使用 addTodo 并传递参数
todolist 更新某个todo完成
- 在 todoItem 组件中 给 inpout 绑定 onChange事件,并传递 id 参数
- 在 todolist 组件中 创建 updateTodo ,循环遍历 todolist原始数据,判断当前传递的id的值是否和遍历的id一致,一致更新对应的todo 的 done值,会得到一个新数组,使用 setTodolist更新数据
- 在 todolist 组件中 将 updateTodo 传递给 todoMain组件
- 在 todoMain 组件中 通过 props 接受 updateTodo
- 在 todoMain 组件中 将 updateTodo 传递给 todoItem组件
- 在 todoItem 组件中 通过 props 接受 updateTodo
- 在 todoItem 组件中 使用 updateTodo,传递 id 和 done
nanoid
作用:一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。 安装:npm i nanoid --force 导入: import { nanoid } from 'nanoid' 使用: nanoid()
前后台数据通信
- 原生js XMLHttpRequest
- jquery ajax()
- react
- axios 基于 Promise 前后台都可以使用
- fetch es6+
axios 请求方式
-
get 获取数据 axios.get("URL地址",{params:{})
-
post 新增数据 axios.post("URL地址",{json数据});
-
put 全部更新数据 axios.put("url地址",{json数据});
-
patch 局部更新数据 axios.patch("url地址",{json数据});
-
delete 删除数据 axios.delete("url地址?id=xxx");
Fragment
react 中的内置组件 作用: 包裹 内部多个虚拟dom 优点: 浏览器不会渲染 Fragment 组件 简写形式: <></>
axios
安装 npm i axios --force 导入 import axios from "axios"
useEffect
useEffect 第一函数类型的参数 不能是异步函数
json-server
作用: 快速搭建后台服务 安装: npm i -g json-server 启动: json-server --watch db.json --port 8888
nprogress
- 安装 npm i nprogress --force
- 导入 import NProgress from "nprogress" import "nprogress/nprogress.css"
- 使用 NProgress.start(); NProgress.done();
then
返回的 Promise 对象
Promise
- 如果 返回的 一个非 Promise 值, Promise 【成功】
- 如果 返回的 一个 Promise 值,且 状态为成功, Promise 【成功】
- 如果 返回的 一个 Promise 值,且 状态为失败, Promise 【失败】
hooks
- useState
- useRef
- useEffect
- useContext 隔代组件数据传递
组件间的数据传递
- props 接受父组件传递的数据
- useContext 隔代组件数据传递
- pubsub-js 发布 订阅 机制 任意组件数据传递
- 路由 (1) URL地址栏 params传参 useParams()接受 特点: url地址比较优雅,会显示数据 heroscon/1/张飞,换个浏览器数据不会丢失 (2) URL地址栏 query 传参 useSearchParams() 接受 特点: url地址不优雅,会显示数据 heroscon?id=1&name=张飞,换个浏览器数据不会丢失 (3) state 传参 useLocation()接受 特点: url地址比较优雅,不会显示数据,数据保存在history状态中, 换个浏览器数据会丢失
react 内置的组件
- React.Fragment <></> 在浏览器中不加载
- countContext.Provider
pubsub-js
作用:发布 订阅 机制 任意组件数据传递
-
安装:npm i pubsub-js --force
-
导入 import PubSub from 'pubsub-js'
-
publish() 发布
publish("数据名称",要发布的数据) -
subscribe() 订阅
PubSub.subscribe("要订阅的消息名称",(订阅的消息名称,订阅的数据)=>{});
-
unsubscribe() 取消订阅
在 组件将要卸载时 取消订阅 PubSub.unsubscribe(要取消的消息名称);
SPA 单页面应用
特点:加载数据少,速度快,不会出现页面空白
路由
作用:解决react 单页面应用
key => value
key: url路径名
value: 组件
react-router-dom
作用:在react 中操作网页路由 版本:React Router 6
- 安装 npm i react-router-dom --force
- 在 App.jsx 导入 import {BrowserRouter,Routes,Route} from "react-router-dom"
react-router-dom 组件
- 包裹所有的路由组件,最外层的路由组件
- 包裹所有的单个路由组件
- 加载单个路由组件
- 链接
- 导航链接
- 二级路由对应的组件占位
- 跳转组件
组件
-
一般组件 存在 components 使用形式:
-
路由组件 存在 pages 使用形式:<Route path="/duanzi" element={ } />
前端验证
用户在网页中所输入的所有数据都是非法的,必须经过验证。
路由中的 hook
- useRoutes() 创建路由对象
- useParams() 接受地址栏中的 params 参数
- useSearchParams() 接受地址栏中的 query 参数
- useLocation() 接受 路由传递的 state 数据
- useNavigate() 编程式路由,返回一个函数 navigate()
路由对象
{ path:"url地址", element:组件 children:子路由 index:入口 meta:{ 路由元信息
}
}
练习一
- 当地址栏 路由 是 heors ,展示英雄列表组件
- 当地址栏 路由 是 heorscon/1 ,展示英雄详情组件
在 路由配置文件中 :
{
path:"/heroscon/:id/:name",
element:<HerosCon/>,
meta:{
title:"英雄详情",
isShow:false
}
}
在 英雄列表组件中
heros.map(item =>{
return (
<Link key={item.id} to={`/heroscon/${item.id}`}>
<li >
<img src={ item.image && `http://cdn.xiaohigh.com${item.image}`}alt="" />
<h3>{item.name}</h3>
</li>
</Link>
)
})
在 英雄详情组件中
//useParams() 接受url地址栏中的 params 参数
let {id} = useParams();
// console.log(obj);
特点: 路由配置 设置的参数 ,使用时,必须对应
练习二
- 当地址栏 路由 是 heors ,展示英雄列表组件
- 当地址栏 路由 是 heorscon?id=1&name="张飞" ,展示英雄详情组件
在路由配置中
{
path:"/heroscon",
element:<HerosCon/>,
meta:{
title:"英雄详情",
isShow:false
}
},
在英雄列表组件中
<Link key={item.id} to={`/heroscon?id=${item.id}&name=${item.name}`}>
<li >
<img src={ item.image && `http://cdn.xiaohigh.com${item.image}`}alt="" />
<h3>{item.name}</h3>
</li>
</Link>
在 英雄详情组件中
// 接受url地址栏中的 query 参数
let [keyword,setKeyword] = useSearchParams();
// console.log(keyword);
let id = keyword.get("id");
// console.log(id);
特点: 灵活
练习三
- 当地址栏 路由 是 heors ,展示英雄列表组件
- 当地址栏 路由 是 heorscon ,展示英雄详情组件 state
在路由配置中
{
path:"/heroscon",
element:<HerosCon/>,
meta:{
title:"英雄详情",
isShow:false
}
},
在英雄列表组件中
<Link key={item.id} to="/heroscon" state={{id:item.id,name:item.name}}>
<li >
<img src={ item.image && `http://cdn.xiaohigh.com${item.image}`}alt="" />
<h3>{item.name}</h3>
</li>
</Link>
在 英雄详情组件中
//接受 路由传递的 state 数据
let location = useLocation();
// console.log(obj)
let {id,name} = location.state;
特点: 地址栏中不显示 传递的数据 state数据保存在 浏览器的 history 对象中
路由懒加载
- 导入 import { lazy, Suspense } from "react";
- 导入组件
// 首页 登录 注册 404 不需要懒加载
import Home from "../pages/Home/Home";
import NotFound from "../pages/NotFound/NotFound";
//懒加载
let Ref = lazy(()=> import("../pages/Ref/Ref"));
let Hooks = lazy(()=> import("../pages/Hooks/Hooks"));
let TodoList = lazy(()=> import("../pages/TodoList/TodoList"));
let Heros = lazy(()=> import("../pages/Heros/Heros"));
let Duanzi = lazy(()=> import("../pages/Duanzi/Duanzi"));
let News = lazy(()=> import("../pages/News/News"));
let Guonei = lazy(()=> import("../pages/News/Guonei"));
let Junshi = lazy(()=> import("../pages/News/Junshi"));
let HerosCon = lazy(()=> import("../pages/HerosCon/HerosCon"));
- 调用懒加载组件
{
path:"/ref",
element:<Suspense fallback={<div>正在加载中...</div>}><Ref/></Suspense>,
meta:{
title:"ref",
isShow:true
}
},
- 封装 load 函数
// 封装
let load = (Comp)=>{
return (
<Suspense fallback={<div>正在加载中...</div>}>
<Comp/>
</Suspense>
)
}
react 中的路由模式
- BrowserRouter
- HashRouter 区别:
- 形式上 BrowserRouter 比较精简 HashRouter 路由地址栏上有锚点 hash #
- 兼容上 BrowserRouter 兼容 IE9 以上的浏览器 HashRouter 兼容 IE8 以上的浏览器
- 项目部署上 BrowserRouter 需要后台人员配置服务器 HashRouter 简单,直接项目打包,放在服务器就可以
redux
集中式状态管理工具 存储一些公共数据 token
- 安装 npm i redux --force
- 导入 import { createStore } from "redux"
// 1. 安装 npm i redux --force
// 2. 导入 createStore 创建数据仓库容器对象
import { createStore } from "redux"
// 3. 创建store 数据仓库
// [1] 存什么数据
// [2] 如何更新数据 action
// action 描述一个行为/动作 值是一个对象 {type:"类型", payload:"更新时存储的数据"}
// 做作业 {type:"做",payload:"作业"}
// 玩游戏 {type:"玩",payload:"游戏"}
// 打酱油 {type:"打",payload:"酱油"}
let store = createStore((count=10,action)=>{
// 加 {type:"incre",payload:1}
// 减 {type:"decre",payload:2}
// swich
switch(action.type){
case "incre":
return count += action.payload; // 返回的内容就是要更新默认数据的值
case "decre":
return count -= action.payload;
// 第一次执行时会返回当前仓库中的默认值
default:
return count;
}
});
// 4. getState 获取数据
console.log(store.getState());
store 数据仓库 方法
- getState() 获取 store 中的数据
- dispatch() 分发行为 (1) 参数是 action 对象,则同步更新 {type:"",payload:""} (2) 参数 是 函数, 则异步更新
- subscribe() 订阅 当 store 仓库中的数据发生变化时候,会自动订阅到。
redux-thunk
作用: 中间件。支持异步更新store 数据
-
安装 npm i redux-thunk --force
-
在 store 中导入 import thunk from "redux-thunk"
-
import { createStore,applyMiddleware } from "redux"
applyMiddleware 作用 应用中间件 -
在 store 第二个参数 应用中间件
let store = createStore((count=0,action)=>{
// 加 {type:"incre",payload:1}
// 减 {type:"decre",payload:2}
// swich
switch(action.type){
case "incre":
return count += action.payload; // 返回的内容就是要更新默认数据的值
case "decre":
return count -= action.payload;
// 第一次执行时会返回当前仓库中的默认值
default:
return count;
}
},applyMiddleware(thunk));
组件展示 store数据过程
-
store,getState() ---> 找到 store , 找reducer ,找 state ,返回给 组件
-
更新数据 store.dispatch() ----> 找到 store , 找reducer , 找 action ,更新 state数据 , 返回给组件
合并reducer 函数
import { createStore,applyMiddleware,combineReducers } from "redux"
combineReducers 合并reduce函数,返回reducer对象
let reducers = combineReducers({
count:countReducer,
zan:zanReducer
})
// 3. 创建store 数据仓库
let store = createStore(reducers,applyMiddleware(thunk));
// 在组件中
// 解构 store 数据
// store.getState(); 获得的是一个store对象
let {count,zan} = store.getState();
新版redux
- 安装 npm install @reduxjs/toolkit --force
- 导入
// createSlice 创建 slice 切片对象 // configureStore 创建 store 对象 import {createSlice,configureStore} from "@reduxjs/toolkit" - 创建 slice 对象 {}
let countSlice = createSlice({
//数据别名
name:"count",
//设置数据初始值
initialState:{ //初始值 新版redux 推荐使用对象
value:0
},
//创建 action 函数
reducers:{
//state === initialState
// action 行为、动作 {type: payload:}
incre:(state,action)=>{
//这里不能返回新数据,要直接更新数据
state.value += action.payload;
},
decre:(state,{payload})=>{
state.value -= payload;
}
}
})
// 4. 提取 action 方法
let {decre,incre} = countSlice.actions;
// 5. 创建 store 对象
let store = configureStore({
reducer:countSlice.reducer
})
// 6. 获取数据
console.log(store.getState());
// 7. 更新数据
console.log(store.dispatch(incre(10)));
console.log(store.getState());
console.log(store.dispatch(decre(5)));
console.log(store.getState());
react-redux
安装 npm i react-redux --force 导入: 在 入口文件 index.js 中导入 import {Provider} from "react-redux"
<Provider store={store}>
当store 中的数据发生变化是,会立即监听到,重新渲染虚拟dom
</Provider >
// useSelector 会获取到store 中的所有数据 // useDispatch 会获取到store 中的dispatch 方法
typescript
安装 npm i -g typescript
- 创建 typescript --> 1. 初体验 ---> hello.ts
- 创建 ts 配置文件 tsc --init
- 转换为js tsc hello.ts
配置 webpack ts 运行环境
- 创建 .gitignore 忽略 node_modules
- 配置启动命令
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start":"npx webpack-dev-server",
"build":"npx webpack"
},
ts版本 react 脚手架
安装 create-react-app 项目名(只能小写) --template typescript 启动: npm start
UI框架
- bootstrap
antd
官网地址: ant.design/docs/spec/i…
安装核心: npm install antd --save
安装 图标库 : npm install --save @ant-design/icons
导入: 按需导入