千峰React:组件与逻辑封装(上)
UI组件库及antd安装
UI组件库就是把页面的组件写好了,用的时候直接调用好了
进行一个安装的动作:
总之就是搭积木,可以调用里面写好的组件库拼接,也可以结合使用
antd布局和导航组件
组件总览 - Ant Design
这是通用部分
在用的时候可以去掉基础样式,其中一个方法就是用antd design里面自带的去基础样式,但是视频的方法是旧版的
制造间隙
使用ant design的响应式布局
import { Row, Col, BackTop } from 'antd'
const col = {
background: 'red',
}
function App() {
return (
<div>
<Row gutter={[10,10]}>//设置水平、竖直间距
<Col xs={12} md={8}>//设置响应尺寸
<div style={col}>aaaaa</div>
</Col>
<Col xs={12} md={8}>
<div style={col}>bbbbb</div>
</Col>
<Col xs={12} md={8}>
<div style={col}>ccccc</div>
</Col>
</Row>
</div>
)
}
export default App
小分辨率的时候一行排两个
打分辨率的时候一行排三个
也可以获取ant design的源码
import { Row, Col, Layout } from 'antd'
import 'antd/dist/reset.css'
const { Header, Footer, Sider, Content } = Layout
const colStyle = {
background: 'red'
}
const headerStyle = {
textAlign: 'center',
color: '#fff',
height: 64,
paddingInline: 50,
lineHeight: '64px',
backgroundColor: '#7dbcea',
};
const contentStyle = {
textAlign: 'center',
minHeight: 120,
lineHeight: '120px',
color: '#fff',
backgroundColor: '#108ee9',
};
const siderStyle = {
textAlign: 'center',
lineHeight: '120px',
color: '#fff',
backgroundColor: '#3ba0e9',
};
const footerStyle = {
textAlign: 'center',
color: '#fff',
backgroundColor: '#7dbcea',
};
function App() {
return (
<div>
hello App
<Row gutter={[10, 10]}>
<Col xs={12} md={8}><div style={colStyle}>aaaaaa</div></Col>
<Col xs={12} md={8}><div style={colStyle}>bbbbbb</div></Col>
<Col xs={12} md={8}><div style={colStyle}>cccccc</div></Col>
</Row>
<Layout>
<Sider style={siderStyle}>Sider</Sider>
<Layout>
<Header style={headerStyle}>Header</Header>
<Content style={contentStyle}>Content</Content>
<Footer style={footerStyle}>Footer</Footer>
</Layout>
</Layout>
</div>
)
}
export default App
六月份学长又说这个不学,我们继续跳
直接学后面的实践
手写antd组件
按钮组件
评分组件
全局提示组件
六月份学长说这一块都别学了
自定义Hook
意思就是自己写一个Hook
写一个获取鼠标定位的hook
import { func } from 'prop-types'
import { useEffect, useState } from 'react'
function useMouse() {
const [state, setState] = useState({
pageX: NaN,
pageY: NaN,
})
useEffect(() => {
function move(e) {
setState({
pageX: e.pageX,
pageY: e.pageY,
})
}
document.addEventListener('mousemove', move)
return () => {
document.removeEventListener('mousemove', move)
}
}, [])
return state
}
function App() {
const mouse = useMouse()
return (
<div>
{mouse.pageX},
{mouse.pageY}
</div>
)
}
export default App
其实这些自定义hooks也被别人写好了,比如ahooks和react-use
下载ahooks
ahooks暂时不支持raect19,所以需要降版本
npm install ahooks//下载ahooks
import { useMouse } from 'ahooks'
function App() {
const mouse = useMouse()
return (
<div>
{mouse.pageX},{mouse.pageY}
</div>
)
}
export default App
ahooks写的功能比我们的更完善,比如clientX,是相对于可视区的x位移
实际开发一般都用人家的ahooks
ahooks处理ajax请求
import { useRequest } from 'ahooks'
import axios from 'axios'
async function getData() {
const res = await axios.get('/cartData.json')
console.log('Response:', res.data) // 检查返回的数据
return res.data.list
}
function App() {
const { data, error, loading } = useRequest(getData)
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
{}
</div>
)
}
export default App
可以从netWork看见axios的网络请求
在这里致谢蚊子咬学长和六月份学长
function App() {
const { data, error, loading } = useRequest(getData)
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
如果网速比较慢还可以看见loading效果
如果访问的地址出错了会出现报错信息
点击的时候才加载获取数据
onSuccess获取响应成功的结果:
const { data, error, loading ,run} = useRequest(getData, {
manual: true,
onSuccess(res) {
console.log(res)
}
})
把响应成功的结果渲染到data里
import { useRequest } from 'ahooks'
import axios from 'axios'
import { useState } from 'react'
async function getData() {
const res = await axios.get('/cartData.json')
console.log('Response:', res.data) // 检查返回的数据
return res.data.list
}
function App() {
const [data, setData] = useState([])
const { error, loading, run } = useRequest(getData, {
manual: true,
onSuccess(res) {
setData(res)
},
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<button onClick={() => run()}>点击</button>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
import { useRequest } from 'ahooks'
import axios from 'axios'
import { useState } from 'react'
async function getData() {
const res = await axios.get('/cartData.json')
console.log('Response:', res.data) // 检查返回的数据
return res.data.list
}
function App() {
const [data, setData] = useState([])
const { error, loading, run, refresh } = useRequest(getData, {
//refresh保留上次ajax的行为
manual: true,
onSuccess(res, params) {
console.log(params)
setData(res)
},
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<button onClick={() => run('run了一次')}>点击</button>
<button onClick={() => refresh('refrash了一次')}>刷新</button>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
上次执行run会log'run了一次',此时再刷新,会记录上次ajax的结果
refresh
:重新执行上一次的请求(包括相同的参数)。
还可以实验mutate修改数据
import { useRequest } from 'ahooks'
import axios from 'axios'
import { useState } from 'react'
async function getData() {
const res = await axios.get('/cartData.json')
console.log('Response:', res.data) // 检查返回的数据
return res.data.list
}
function App() {
const {data ,error, loading, mutate } = useRequest(getData)
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<button onClick={() => mutate([{ 'id': 1, 'name': '榴莲' }])}>点击修改数据</button>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
之前写的聊天室切换功能,因为加载时间不同,最后是用useEffect解决的,但是比较麻烦,需要新变量,每次还要做判断
而aHooks的useRequest已经做好内部的清理工作了
import { useRequest } from 'ahooks'
import { useState, useEffect } from 'react'
function fetchChat(title) {
const delay = title === '电磁场与电磁波' ? 2000 : 1000
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ id: 1, text: title + '1' },
{ id: 2, text: title + '2' },
{ id: 3, text: title + '3' },
])
}, delay)
})
}
function Chat({ title }) {
const { data, error, loading } = useRequest(() => fetchChat(title), {
refreshDeps:[title]//一旦title改变,重新发起ajax请求
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
{data.map((item) => {
return <li key={item.id}>{item.text}</li>
})}
</div>
)
}
function App() {
const [show, setShow] = useState(true)
const [title, setTitle] = useState('电磁场与电磁波')
const handleClick = () => {
setShow(false)
}
const handleChange = (e) => {
setTitle(e.target.value)
}
return (
<div>
<button onClick={handleClick}>点我退出课堂</button>
<select value={title} onChange={handleChange}>
<option value='电磁场与电磁波'>电磁场与电磁波</option>
<option value='半导体物理'>半导体物理</option>
</select>
{show && <Chat title={title} />}
</div>
)
}
export default App
ahooks处理请求的高级用法
轮询
import { useRequest } from 'ahooks'
import axios from 'axios'
async function getData() {
const res = await axios.get('/cartData.json')
return res.data.list.sort(() => Math.random() - 0.5)
}
function App() {
const { data, error, loading } = useRequest(getData, {
pollingInterval: 3000,//轮询获取数据,3秒一次
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<ul>
{data&&data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
)
}
export default App
三秒一次请求
可以防止频闪,具体来说就说加入
loadingDelay: 1000
这行语句,页面渲染的时间如果不在1s内,就会显示加载界面:loading
如果渲染时间在1s内,就不会显示loading,优化页面
不加防抖,每次点击按钮都会获取数据
import { useRequest } from 'ahooks'
import axios from 'axios'
async function getData() {
const res = await axios.get('/cartData.json')
return res.data.list.sort(() => Math.random() - 0.5)
}
function App() {
const {data, run, error, loading } = useRequest(getData, {
manual: true,
onSuccess(ret) {
console.log(ret)
}
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<button onClick={run}>点击</button>
<ul>{data && data.map((item) => <li key={item.id}>{item.name}</li>)}</ul>
</div>
)
}
export default App
加上防抖以后只会执行最后一次的效果
const { data, run, error, loading } = useRequest(getData, {
manual: true,
debounceWait: 300,
onSuccess(ret) {
console.log(ret)
},
})
除了防抖,还有节流,节流是降低触发频率:
import { useRequest } from 'ahooks'
import axios from 'axios'
async function getData() {
const res = await axios.get('/cartData.json')
return res.data.list.sort(() => Math.random() - 0.5)
}
function App() {
const { data, run, error, loading } = useRequest(getData, {
manual: true,
throttleWait: 1000,
// debounceWait: 300,
onSuccess(ret) {
console.log(ret)
},
})
if (error) {
return <div>{error.message}</div>
}
if (loading) {
return <div>loading...</div>
}
return (
<div>
<button onClick={run}>点击</button>
<ul>{data && data.map((item) => <li key={item.id}>{item.name}</li>)}</ul>
</div>
)
}
export default App
触发太多次,都按照设定的时间1秒一次,一秒内一次也没有触发就不执行
离开窗口再回到窗口会再次发起请求
从缓存里取数据,不用重新加载
ahooks处理业务场景
import { useHistoryTravel } from "ahooks";
function App() {
const { value='', setValue, backLength, forwardLength, back, forward } =
useHistoryTravel()
return (
<div>
<input type='text' value={value} onChange={(e)=>setValue(e.target.value)}/>
<button disabled={backLength <= 0} onClick={back}>后退</button>
<button disabled={forwardLength<= 0} onClick={forward}>前进</button>
<br />
{value}
</div>
)
}
export default App
可以控制e.target.value控制输入框的内容到页面渲染上
import { useDynamicList } from "ahooks";
import { MinusCircleOutlined ,PauseCircleOutlined} from "@ant-design/icons";
function App() {
const { list, remove,insert, replace } = useDynamicList(['David', 'Jack']);
return (
<div>
{list.map((item, index) => {
return (
<div key={index}>
<input type="text" value={item} onChange={ (e)=>replace(index,e.target.value)} />
<MinusCircleOutlined />
<PauseCircleOutlined/>
</div>
)
})}
<br />
<ul>
{list.map((item, index) => (
<li key={index}>
{item}
</li>
))}
</ul>
</div>
)
}
export default App
加入删除和增添功能
import { useDynamicList } from "ahooks";
import { MinusCircleOutlined ,PlusCircleOutlined} from "@ant-design/icons";
function App() {
const { list, remove,insert, replace } = useDynamicList(['David', 'Jack']);
return (
<div>
{list.map((item, index) => {
return (
<div key={index}>
<input type="text" value={item} onChange={ (e)=>replace(index,e.target.value)} />
<MinusCircleOutlined onClick={()=>remove(index)}/>
<PlusCircleOutlined onClick={() => insert(index+1,'')} />
</div>
)
})}
<br />
<ul>
{list.map((item, index) => (
<li key={index}>
{item}
</li>
))}
</ul>
</div>
)
}
export default App