React
写在前面
- 这是我学习完react,并用react做了四个小项目之后进行的总结与复盘,很多东西都只是简单地提一嘴,并不会深入地分析,有不妥之处请多多指教
- 现在react提倡使用函数式组件,并且由于我对于类不熟悉,学习react的时候对类组件编程不太上心,因此我下面说的大部分都是基于函数式组件的
- hook(用在函数式组件里面的)我说到的的只有几个我自己比较熟悉的以及常用的(useState,useEffect,useLocation,useRoutes ),其他的还有useReducer,useContext,useRef,useRef,useMemo,useLayoutEffect以及自定义hook
- 我下面的代码都是建立在脚手架上面的
- 新手上路~~~
React是什么 React的特点
- react是一个将数据渲染为HTML视图的开源JavaScript库
- React使用虚拟DOM+优秀的Diffing算法,尽量减少与真实DOM的交互(我们在使用react的过程中,可以不操作真实DOM就不要)
- react提倡将功能函数内联在html代码中
jsx
- jsx语法的代码使用来编写组件的,也可以说是用来写html代码的,然后在html代码中嵌入功能函数
- 语法规则:
标签中混入JS表达式的时候要用{}将js代码包起来
jsx中只有一个根标签
jsx中标签必须闭合 - 注意:区分“js语句”和“js表达式”
js表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,a、a+b、arr.map()、function test(){ }等
js语句:if(){ }、for(){ }等
state
-
状态:每一次状态的改变都会影响到整一个组件,包括子组件,比如说在代码的最后面修改了状态,在前面用到这个状态的逻辑也会执行一遍(实际上是每次状态改变都会从头“执行”一遍我们的代码)
-
state初始化:
使用useState进行初始化。
形式如下:const [yourState,setYourState]=useState(‘’)
yourState是你自己的state的名字,setYourState是用于改变state的,useState括号里面是state的初始值 -
改变state的值:state的值是不可以用普通方式改变的,改变state的值只能通过声明state时候的setYourState
-
具体实例:
import React,{ useState } from 'react'
// state初始化
const [allFrames,setAllFrames]=useState(1);
const [file,setFile]=useState(null);
const [isModalVisible, setIsModalVisible] = useState(false);
// 改变state
setFile(file);
setAllFrames(allFrames + 1);
props
- props主要用于父组件向子组件传递信息 以及路由跳转组件的时候传递信息
- 具体用例:
// 父组件文件
import React from 'react';
export default function AlExe() {
return (
<MySelect option={['true','false']}/>
)
}
// 子组件文件
import { Select } from 'antd';
import React from 'react';
// props可以在子组件中直接获取直接使用 但是要先在函数的参数位置放上去
export default function MySelect(props) {
console.log('props ->',props);
return (
<div>MySelect</div>
)
}
useEffect
- 第一个参数接收一个函数,在组件更新的时候执行,函数返回值是一个函数
- 第二个参数接收一个数组,用来表示需要追踪的变量,依赖列表,只有依赖更新的时候才会更新内容;没有依赖的时候就进入时执行一次(但是经常会有进入时执行两遍的情况??)
import React,{ useEffect,useState } from 'react';
export default function Test() {
const [count,setCount]=useState(0);
function handleClick(){
setCount(count + 1);
}
useEffect(() => {
console.log('[count]被调用了');
}, [count])
useEffect(() => {
console.log('[]被调用了');
}, [])
return (
<div onClick={handleClick}>Test</div>
)
}
函数柯里化与高阶函数
- 函数柯里化:通过函数调用继续返回函数的方式,实现多次接受参数最后统一处理的函数编码方式
- 高阶函数:如果一个函数符合下面2个规范的任何一个,那该函数就是高阶函数
若A函数,接受的参数是一个函数,那么A就可以称之为高阶函数
若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数
不用柯里化的可以直接箭头函数返回一个函数的调用
function handleBlur(e){
console.log(e.target.value);
}
// 涉及到函数的闭包 还有点模糊
// 调用箭头函数 传参Event给箭头函数 Event再传给handleBlur并返回handleBlur的调用
<input onBlur=((Event)=>{handleBlur(Event)}>
// 函数声明
function handleDetail(value){
console.log(value);
}
// 这两个不能直接用的哈 只是演示一下这样的传参方式
{
arr.map(i => {
return ({
// 使用箭头函数传参 调用箭头函数 返回一个函数的调用
// 这里的参数是直接传给handleDtail函数的
<a onClick={() => handleDetail(i)}>详细信息</a>
})
});
}
生命周期
- 生命周期我目前用得不多
Diffing算法
- Diffing算法对比的最小力度是标签,就是说标签里面的文本是不对比的
- key是虚拟DOM对象的标识,在更新时key起着及其重要的作用
- 当状态中的数据发生变化的时候,react会根据“新数据”生成“新的虚拟DOM”,随后react进行新旧虚拟DOM的diff比较(比较key),决定是否生成生成/替换真实DOM
- 选择key,最好使用每条数据的唯一标识作为key(不变的)
脚手架
- 我一般用VSCode的终端来执行命令 电脑命令行也是可以的
- 我一般用npm来执行命令的 用yard也是可以的
- 全局安装脚手架 这个只要安装过一次就好了
$ npm i-g create-react-app
- 切换到想创建项目的目录 下面的hello-react是项目名 你自己决定
$ create-react-app hello-react
- 启动项目 记住一定要进入项目文件夹再启动项目
我遇到过的一个坑是创建完项目就立即启动项目 结果就报错了 !!
应该先进入项目文件夹 创建完项目之后并不会帮你自动进入到项目文件夹的
$ npm start
- 项目打包 项目打包后才可以部署到服务器上面
$ npm run build
redux
- redux在小项目中可能用不到,但是在大项目中会用得到,目前还没有做过大项目 ,因此redux目前我不熟,就先不展开了
- redux是用来在组件间通信的
路由(下面写的是React Router 6)
react-router-dom
- react-router-dom是react中的一个库
- 基本项目中都会用到,但是需要手动安装
$ npm i react-router-dom
内置路由
- < BrowserRouter > 路由 一般不用这个 哈希路由相对来说好用点
- < HashRouter > 哈希路由 使用这个路径上面会有一个# 一般用这个
- < Router >
- < Redirect >
- < Link >
- < NavLink >
- < Routers >
路由的固定结构
路由定位
- element用于放置由路由导进来的组件,不然路径是会改变,但是组件并不会出现
import React from 'react';
import { useRoutes } from 'react-router-dom'
import routes from './routes'
import Head from './component/head';
export default function App() {
const element = useRoutes(routes);
return (
<div>
<Head />
{element}
</div>
)
}
路由包裹
- src文件夹下的index.js文件中
- 用< HashRouter >或者< BrowserRouter >将组件包裹起来路由才能发挥作用
- 一般项目开发中,直接包裹最外面的那个组件(< App/ >),我一般用< HashRouter >,虽然路径看起来没有那么清爽,但是功能更加强大,< HashRouter >本质是锚点?
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { HashRouter } from 'react-router-dom';
root.render(
<React.StrictMode>
<HashRouter><App /></HashRouter>
</React.StrictMode>
);
路由表
- 路由表一般放在routes文件夹里面,命名为index.js
- 一般都将路由统一在路由表里面配置
import React from 'react'
import { Navigate } from 'react-router-dom'
import Dlzc from '../pages/logandreg'
import Adminl from '../component/adminl'
import Register from '../component/register'
import ManageUser from '../pages/manageUser'
const routes = [
{
// 以及路由的路径是带'/'的 意义是‘当前路径下’?
path: '/dlzc',
element: <Dlzc />,
children: [
// 二级路由(嵌套路由)是不带'/'的 意义是'从头开始查找'?
{
path: 'namel',
element:<Namel/>,
},
{
path: 'register',
element:<Register/>
},
{
path: '',
element: <Navigate to='namel' />
}
]
},
{
path: '/manageUser',
element: <ManageUser />,
},
// 这样做的意义是默认导向 Navigate用于重定向
{
path: '',
element: <Navigate to='ManageUser'>
}
]
export default routes
子路由
- 一级路由出现的地方是{element}, 子路由(嵌套路由)出现的地方是
- 如果没有< Outlet/ >,触发路由之后路径是会改变,但是组件不会出现
import React from 'react'
// 导出Outlet
import { Outlet } from 'react-router-dom'
export default function Dlzc() {
return (
<div>
<Outlet />
</div>
)
}
Link和NavLink
- Link和NavLink的区别:两者的区别在于NavLink在点击时会有自带的active属性
- 前提:
路由事先在路由表中注册好
{element}或者< Outlet/ >已经放好了 - 具体使用:
<NavLink to='namel'>用户登录</NavLink>
<Link to='register'>用户注册</Link>
重定向:useNavigate与useLocation(这两个是hook,用于函数式组件的)
- 前提:
路由事先在路由表中注册好
{element}或者< Outlet/ >已经放好了
// LogPack文件夹中的index.jsx
import React from 'react'
// 1. 导出useNavigate
import { useNavigate } from 'react-router-dom';
export default function LogPack() {
// 2. 定义navigate
const navigate = useNavigate();
const data=[{name:'kkt',age:18},{name:'xiaoming',age:18}];
function handleDetail() {
// 使用navigate进行重定向 state用于传递参数
navigate('/logdetail', { state: data});
}
return (
// 点击这个链接 调用了handleDetail函数 重定向至另一个组件(将当前组件换成了另一个组件)
// 组件的放置的位置仍然是{element}
<a onClick={handleDetail}>详细信息</a>
)
}
// LogDetail文件夹中的index.jsx
import React from 'react'
// 1. 导入useLocation
import { useLocation } from 'react-router-dom'
export default function LogDetail() {
// 2. useLocation().state就是传过来的数据 state是键
console.log(useLocation().state);
return (
<div>logDetail</div>
)
}
组件库
- antd是一个很好用的组件库,有很多小组件实用性都较好,表格也做得不错,文档页写得不错自己也可以对antd的组件进行封装,提高代码的复用率,附上antd传送门
- antV主要用于数据的可视化,文档写得不错,附上antV传送门
- echarts是一个图表库,功能很强大,文档个人认为有点难懂,附上ECharts传送门,想要使用基于ECharts基于react的封装,得走这里,这个是ECharts的react封装的一个库,在github上面的
注意
- '…'运算符(展开运算符)
展开运算符很好用,包括在对象中、数组中,在很多地方都是可以用到展开运算符的。
展开运算符用于展开一个可迭代对象(比如数组…arr),或者{…data},data是一个对象,这样的用法相当于浅复制一个对象 - JavaScript中的众多方法,特别是数组的很多方法在react中都是很有必要的
- ES6在react中也得用得相当顺手
- 一般组件文件夹以组件名来命名,而组件文件均以index.jsx命名