react类型定义表+redux Toolkit使用方法

2023-01-01 08:45:25

类型定义速查表

React.FC<Props> | React.FunctionComponent<Props>

  • 表示功能组件的类型
const  MyComponent:react.FC <props>  = ...

React.Component<Props, State>

  • 表示类组件的类型
class MyComponent extends React.Component<Props, State> { ...

React.ComponentType<Props>

  • 表示 (React.FC | React.Component) 联合的类型 - 在 HOC 中使用
const withState = <P extends WrappedComponentProps>(
  WrappedComponent: React.ComponentType<P>,
) => { ...

React.ComponentProps<typeof XXX>

  • 获取指定组件 XXX 的道具类型(警告:不适用于静态声明的默认道具和通用道具)
type MyComponentProps = React.ComponentProps<typeof MyComponent>;

React.ReactElement | JSX.Element

  • 表示 React Element 概念的类型 - 表示原生 DOM 组件(例如
    ),或用户定义的复合组件(例如)
const elementOnly: React.ReactElement = <div /> || <MyComponent />;

React.ReactNode

  • 代表任何可能类型的 React 节点的类型(基本上是 ReactElement(包括 Fragment 和 Portal)+原始 JS 类型)
const elementOrPrimitive: React.ReactNode = 'string' || 0 || false || null || undefined || <div /> || <MyComponent />;
const Component = ({ children: React.ReactNode }) => ...

React.CSSProperties

  • 在 JSX 中表示样式对象的类型 - 用于 css-in-js 样式
const styles: React.CSSProperties = { flexDirection: 'row', ...
const element = <div style={styles} ...

React.HTMLProps<HTMLXXXElement>

  • 表示指定 HTML 元素的道具的类型 - 用于扩展 HTML 元素
const Input: React.FC<Props & React.HTMLProps<HTMLInputElement>> = props => { ... }

<Input about={...} accept={...} alt={...} ... />

React.ReactEventHandler<HTMLXXXElement>

  • 表示通用事件处理程序的类型 - 用于声明事件处理程序
const  handleChange:react.ReactEventHandler < HTMLInputElement >  =  ( ev )  =>  { ... }  

< input  onChange = { handleChange } ... / >

React.XXXEvent<HTMLXXXElement>

  • 代表更具体事件的类型。一些常见的事件示例:ChangeEvent, FormEvent, FocusEvent, KeyboardEvent, MouseEvent, DragEvent, PointerEvent, WheelEvent, TouchEvent.
const  handleChange  =  ( ev : React . MouseEvent < HTMLDivElement > )  =>  { ... } 

< div  onMouseMove = { handleChange } ... / >

redux Toolkit使用方法

  • 目录结构
    在这里插入图片描述
  • store/index
// redux store 常规配置方法
// import { applyMiddleware, createStore } from 'redux'
// import { composeWithDevTools } from 'redux-devtools-extension'
// import thunkMiddleware from 'redux-thunk'

// import monitorReducersEnhancer from './enhancers/monitorReducers'
// import loggerMiddleware from './middleware/logger'
// import rootReducer from './reducers'

// export default function configureStore(preloadedState) {
//   const middlewares = [loggerMiddleware, thunkMiddleware]
//   const middlewareEnhancer = applyMiddleware(...middlewares)

//   const enhancers = [middlewareEnhancer, monitorReducersEnhancer]
//   const composedEnhancers = composeWithDevTools(...enhancers)

//   const store = createStore(rootReducer, preloadedState, composedEnhancers)

//   if (process.env.NODE_ENV !== 'production' && module.hot) {
//     module.hot.accept('./reducers', () => store.replaceReducer(rootReducer))
//   }

//   return store
// }

// import { createStore, applyMiddleware, compose } from 'redux'
// import thunk from 'redux-thunk'
// import * as reducer from './reducer'
// const composeEnhancers =
//   (typeof window !== 'undefined' &&
//     window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
//   compose
// export default createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
import { configureStore, MiddlewareArray } from '@reduxjs/toolkit'
import counterReducer from './features/counter/counterSlice'
// import logger from 'redux-logger'
// import additionalMiddleware from 'additional-middleware'
// import monitorReducersEnhancer from './enhancers/monitorReducers'
// // @ts-ignore
// import untypedMiddleware from 'untyped-middleware'

export const store: any = configureStore({
  reducer: {
    counter: counterReducer
  }
  // 中间件
  // 如果你提供了 middleware 参数,则 configureStore 将仅使用你列出的 middleware。
  // 如果你想同时拥有自定义的 以及 默认的 middleware,
  // 你可以调用 getDefaultMiddleware 并将结果包括在你提供的 middleware 数组中。
  // middleware: (getDefaultMiddleware) =>
  //   getDefaultMiddleware()
  //     .prepend(
  //     // correctly typed middlewares can just be used
  //       additionalMiddleware,
  //     // you can also type middlewares manually
  //     untypedMiddleware as Middleware<
  //       (action: Action<'specialAction'>) => number,
  //       RootState
  //     >
  //     )
  //   // prepend and concat calls can be chained
  //     .concat(logger),

  // middleware: new MiddlewareArray().concat(additionalMiddleware, logger),
  // 写法不同,与上述写法功能相同
  // middleware: [additionalMiddleware, logger] as const

  // preloadedState(初始化state)是如何控制单一或通过combineReducer组合生成的reducer中
  // 手动加的state的默认值是否生效的
  // preloadedState,

  // enhancer (Function): Store enhancer 是一个组合 store creator 的高阶函数,返回一个新的强化过的 store creator。
  // 这与 middleware 相似,它也允许你通过复合函数改变 store 接口。
  // enhancers: [monitorReducersEnhancer]
})

// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch

  • store/features/counter/couterSlice
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { fetchCount } from '../../../services/counterAPI'

const initialState = {
  value: 0,
  status: 'idle'
}

// The function below is called a thunk and allows us to perform async logic. It
// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This
// will call the thunk with the `dispatch` function as the first argument. Async
// code can then be executed and other actions can be dispatched. Thunks are
// typically used to make async requests.
export const incrementAsync = createAsyncThunk(
  'counter/fetchCount',
  async (amount) => {
    const response = await fetchCount(amount)
    // The value we return becomes the `fulfilled` action payload
    return response.data
  }
)

export const counterSlice = createSlice({
  name: 'counter',
  initialState,
  // The `reducers` field lets us define reducers and generate associated actions
  reducers: {
    increment: (state) => {
      // Redux Toolkit allows us to write "mutating" logic in reducers. It
      // doesn't actually mutate the state because it uses the Immer library,
      // which detects changes to a "draft state" and produces a brand new
      // immutable state based off those changes
      state.value += 1
    },
    setStatus: (state) => {
      if (state.loading === 'idle') {
        state.loading = 'pending'
      }
    },
    usersReceived (state, action) {
      if (state.loading === 'pending') {
        state.loading = 'idle'
        state.value = action.payload
      }
    },

    decrement: (state) => {
      state.value -= 1
    },
    // Use the PayloadAction type to declare the contents of `action.payload`
    incrementByAmount: (state, action) => {
      state.value += action.payload
    }
  },
  // The `extraReducers` field lets the slice handle actions defined elsewhere,
  // including actions generated by createAsyncThunk or in other slices.
  extraReducers: (builder) => {
    builder
      .addCase(incrementAsync.pending, (state) => {
        state.status = 'loading'
      })
      .addCase(incrementAsync.fulfilled, (state, action) => {
        state.status = 'idle'
        state.value += action.payload
      })
  }
})

export const { increment, decrement, incrementByAmount, setStatus, usersReceived } = counterSlice.actions

// The function below is called a selector and allows us to select a value from
// the state. Selectors can also be defined inline where they're used instead of
// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)`
export const selectCount = (state) => state.counter.value

// We can also write thunks by hand, which may contain both sync and async logic.
// Here's an example of conditionally dispatching actions based on current state.
export const incrementIfOdd = (amount) => (dispatch, getState) => {
  const currentValue = selectCount(getState())
  if (currentValue % 2 === 1) {
    dispatch(incrementByAmount(amount))
  }
}

export default counterSlice.reducer

// 定义一个 thunk 派发那些 action creators 异步方法
// const fetchUsers = () => async dispatch => {
//   dispatch(setStatus())
//   const response = await fetchCount()
//   dispatch(usersReceived(response.data))
// }

  • services/couterAPI
// A mock function to mimic making an async request for data
export function fetchCount (amount = 1) {
  return new Promise((resolve) =>
    setTimeout(() => resolve({ data: amount }), 500)
  )
}

  • hooks/useRedux
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from '../store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
  • 使用方法 pages/reudx
import React, { ReactElement } from 'react'
import { useAppSelector, useAppDispatch } from '@/hooks/useRedux'
import { decrement, increment, incrementByAmount } from '../../store/features/counter/counterSlice'

export default function Redux (): ReactElement {
  const count = useAppSelector((state) => state.counter.value)
  const dispatch = useAppDispatch()
  const add = () => {
    console.log(count)
    // dispatch(increment())
    // dispatch.counter.decrement()
    dispatch(incrementByAmount(3))
  }
  return (
    <div>
      {count}
      <button onClick={add}>按钮</button>
    </div>
  )
}

  • 效果
    在这里插入图片描述
  • 作者:MaxLoongLvs
  • 原文链接:https://blog.csdn.net/shadowfall/article/details/121774292
    更新时间:2023-01-01 08:45:25