toolkit+router6+typescript项目笔记

React组件首字母需要大写

useState和useRef用哪个

useState会触发页面更新,useRef不会

Partial

// Partial可以将所有属性变成可选的
export type UserinfoPatchBody = Partial<UserInfo>

css属性中的user-select

user-select 属性规定是否能选取元素的文本。

在 web 浏览器中,如果您在文本上双击,文本会被选取或高亮显示。此属性用于阻止这种行为。

sass

定义变量 要用$开头

@mixin与@include配合使用

column-gap: 40px;

指定列之间的的间隙为 40 个像素:

SEO优化

				<img src={logo} alt="测评系统" />
				<h1 style={{ fontSize: 0 }}>测评系统</h1>

图片地址以//开头

1、它会判断当前的页面协议是http 还是 https 来决定请求 url 的协议。

2、用于处理 网站使用的协议和 网页中请求的外网资源不一致的问题。

3、这种写法,也使用于CSS

React.Fragment

React.Fragment组件能够在不额外创建 DOM 元素的情况下,让 render()方法中返回多个元素。相当于空标签<></>。

alias @设置为src路径

在ts.config.json中再配置

图片不显示问题

如果没有将图片放入public文件夹下,在其他文件夹下通过img标签使用会出现图片不显示问题,

这个时候使用import导入的方式即可使用

import logo from './assets/logo.png'

路由

可以把路由信息放入config.ts中,在App.tsx中导入使用

type RouterDataType=typeof RouterData
export type RouterKeys=keyof RouterDataType


// 路由信息
export const RouterData={
  // 单词应该为correct
  corret_exam_list:{
    path:'/corret_exam_list'
  },
  subject_add:{
    path:'/subject_add'
  },
  subject_manage:{
    path:'/subject_manage'
  },
  student_manage:{
    path:'/student_manage'
  }
}

设置监听当前路由变化的hooks

import { useLocation } from 'react-router-dom';

// 监视当前路由的变化
export function usePathKey(){
   let location=useLocation()
   
   let pathKey=location.pathname


   return pathKey
}

倒计时

通过useEffect进行对count监听

  // 设置倒计时
  const [count, setCount] = useState(0)
  // 验证码倒计时
  let TIME = 60

  // 倒计时
  useEffect(() => {
    if (count === 0) return
    setTimeout(() => {
      setCount(count - 1)
    }, 1000)
  }, [count])

  // 获取验证码
  const startCode = () => {
    form
      .validateFields(['username'])
      .then(() => {
        setCount(TIME)
      })
      .catch(() => {})
  }

阻止冒泡

   <span className={styles.delete} onClick={e => deleteSubjectTwo(e, item)}>
                删除
              </span>
// 删除题目
  const deleteSubjectTwo = async (e: any, item: any) => {
    e.stopPropagation()
    const res = await request.delete(`/api/topic/${item._id}`)
    if (res.status === 200) {
      message.success('删除成功')
    }
    dispatch(set_active_topic(null))
    dispatch(get_topic_list_async(item.two_id))
  }

给每个孩子循环添加key

// 循环添加key
function addSubjectTreeKey(subject_tree: any) {
  const _tree = JSON.parse(JSON.stringify(subject_tree))
  const data = _tree.map((item: any) => {
    let children
    item.key = item.value
    if (item.children?.length > 0) {
      children = addSubjectTreeKey(item.children)
    }
    return {
      ...item,
      children
    }
  })
  return data
}

对props定义类型

父组件

<AddSubjectTwo showing={isModalOpen} changeShowing={changeModal}></AddSubjectTwo>

子组件

type AddSubjectTwoType = {
  showing: boolean
  changeShowing: (a: boolean) => void
}

// 内嵌表格
export default function AddSubjectTwo({ showing, changeShowing }: AddSubjectTwoType) {}

变量后使用 !

变量后使用 !:表示类型推断排除null、undefined

// 变量后使用 !:表示类型推断排除null、undefined
      const fileName = avatar.split('/').at(-1)!

No routes matched location

错误写法

 // 阅卷
  corret_exam: {
    path: '/corret_exam',
    hasMenu: false
  }

正确写法

  // 阅卷
  corret_exam: {
    path: '/corret_exam/:exam_id',
    hasMenu: false
  }

可以将参数放入路径的后面作为传参的方式,这样避免刷新导致参数消失,放入redux中就会产生这种问题

  // 前往阅卷
  function goCorretExam(record: any) {
    // 采用此方式刷新后就会导致数据消失
    // dispatch(set_current_exam_topic_id(record._id))
    // 通过 路由传过去可以防止刷新数据消失
    navigate(`/corret_exam/${record._id}`)
  }

useEffect

有些解决不了的问题可以通过useEffect巧妙的解决,只要在[]后填上合理的参数

classNames

下载classnames的包

然后使用

<div className={`${styles.wrap} ${classNames({ read: type === 'read' })}`}>

事件总线处理状态码等问题

下载events包

在util文件夹下创建event.js文件

import { EventEmitter } from "events";

// 全局发布订阅
const eventBus = new EventEmitter()

export default eventBus

在响应拦截器中进行使用

// 响应拦截器
instance.interceptors.response.use(
  function (response) {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    console.log('响应状态码', response.status)

    if (response.status === 200) {
      // 401未登录
      if (response.data.code === 401) {
        eventBus.emit('global_not_login', response.data.msg)
      }

      // 业务错误
      if (response.data.code === -1) {
        eventBus.emit('global_error_tips', response.data.msg)
      }
    } else if (response.status === 403) {
      eventBus.emit('global_error_auth', '没有权限,爬一边去')
    }

    return response
  },
  function (err) {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    // console.log('响应拦截器中的失败响应', err.response.status)
    eventBus.emit('global_error_tips', err.response.data.msg)

    return Promise.reject(err)
  }
)

然后在App.tsx中接收

// 处理错误的函数
const openNotification = (msg: string) => {
  notification.error({
    message: '错误',
    description: `错误信息:${msg}`
  })
}

function App() {
  const dispatch = useAppDispatch()
  const navigate = useNavigate()

  // 获取用户信息
  useEffect(() => {
    dispatch(get_user_info_async())

    // 未登录
    eventBus.on('global_not_login', function (msg) {
      navigate('/login')
      openNotification('哥你至少得登录吧')
    })

    // 业务错误
    eventBus.on('global_error_tips', function (msg) {
      openNotification(msg)
    })

    // 没有权限
    eventBus.on('global_error_auth', function (msg) {
      openNotification(msg)

      LogoutPost().then(() => {
        navigate('/login')
      })
    })
  }, [])
...

懒加载

// 懒加载
const AsyncSubjectAdd = lazy(() => import('./pages/subject_add'))
const AsyncSubjectManage = lazy(() => import('./pages/subject_manage'))

// Suspense与lazy配合shiyong
function SubjectManage() {
  return (
    <Suspense fallback={'loading'}>
      <AsyncSubjectManage></AsyncSubjectManage>
    </Suspense>
  )
}

function SubjectAdd() {
  return (
    <Suspense fallback={'loading'}>
      <AsyncSubjectAdd></AsyncSubjectAdd>
    </Suspense>
  )
}

统计渲染次数的hooks

import { useRef } from 'react'

// 渲染次数统计
export default function useRenderCount(name: string) {
  const ref = useRef(0)
  ref.current++
  console.log(`${name}已经渲染了${ref.current}次`)
}

进入新页面后仍存在上个页面的数据

useEffect的中return函数为componentWillUnmount生命周期

下载js-cookie

js-cookie是获取Cookie的值

ErrorBoundary

import React, { Component } from 'react'

// 组件渲染错误处理,可以放入全局中比如index.tsx  或者单独放入复杂或者不稳定的组件
export default class ErrorBoundary extends Component {
  state: any
  props: any

  constructor(props: any) {
    super(props)
    this.state = { hasError: false }
  }

  static getDerivedStateFromError(error: any) {
    return { hasError: true }
  }

  render() {
    if (this.state.hasError) {
      return <h1>鸽鸽,页面出错啦</h1>
    }
    return this.props.children
  }
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值