千峰React:组件与逻辑封装(上)

UI组件库及antd安装

UI组件库就是把页面的组件写好了,用的时候直接调用好了

进行一个安装的动作:

总之就是搭积木,可以调用里面写好的组件库拼接,也可以结合使用

antd布局和导航组件

组件总览 - Ant Design

这是通用部分

在用的时候可以去掉基础样式,其中一个方法就是用antd design里面自带的去基础样式,但是视频的方法是旧版的

制造间隙

使用ant design的响应式布局

javascript 复制代码
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的源码

javascript 复制代码
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

javascript 复制代码
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,所以需要降版本

javascript 复制代码
npm install ahooks//下载ahooks
javascript 复制代码
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请求

javascript 复制代码
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的网络请求

在这里致谢蚊子咬学长和六月份学长

javascript 复制代码
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获取响应成功的结果:

javascript 复制代码
 const { data, error, loading ,run} = useRequest(getData, {
        manual: true,
        onSuccess(res) {
            console.log(res)
        }
    })

把响应成功的结果渲染到data里

javascript 复制代码
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
javascript 复制代码
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修改数据

javascript 复制代码
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已经做好内部的清理工作了

javascript 复制代码
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处理请求的高级用法

轮询

javascript 复制代码
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

三秒一次请求

可以防止频闪,具体来说就说加入

javascript 复制代码
     loadingDelay: 1000

这行语句,页面渲染的时间如果不在1s内,就会显示加载界面:loading

如果渲染时间在1s内,就不会显示loading,优化页面

不加防抖,每次点击按钮都会获取数据

javascript 复制代码
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

加上防抖以后只会执行最后一次的效果

javascript 复制代码
const { data, run, error, loading } = useRequest(getData, {
    manual: true,
    debounceWait: 300,
    onSuccess(ret) {
      console.log(ret)
    },
  })

除了防抖,还有节流,节流是降低触发频率:

javascript 复制代码
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处理业务场景

javascript 复制代码
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控制输入框的内容到页面渲染上

javascript 复制代码
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

加入删除和增添功能

javascript 复制代码
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
相关推荐
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅4 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊5 小时前
jwt介绍
前端
爱敲代码的小鱼5 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax