在react中简单使用TS

563 阅读3分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路

注:本文有部分基础没有写,但主体内容均已列出,如参考请做好心理准备

image.png

1.创建单个action库

src\store\reducers\todos.ts

const initState=[
  {
    id:1,
    name:'学习',
    isDone:false
  },
  {
    id:2,
    name:'玩',
    isDone:false
  },
  {
    id:3,
    name:'睡觉',
    isDone:false
  }
] 
export default function todos(state=initState,action:any){
  return state
}

2.合并action库

src\store\reducers\index.ts

import { combineReducers } from "redux";
import todos from "./todos";
const rootReducer=combineReducers({
  todos
})
export default rootReducer

3.配置redux

src\store\index.ts

import { applyMiddleware,legacy_createStore } from "redux";
import rootReducer from './reducers'
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
 const store=legacy_createStore(rootReducer,composeWithDevTools(applyMiddleware(thunk)))
export default store

4.挂载到状态树上

src\index.tsx

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import store from './store';
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

5.获取数据

方式1

App

image.png

方式2

APP

image.png

方式3

typeof

typeof可以获取某个数据的类型

type Fn = typeof fn获取fn函数的类型

ReturnType

ReturnType是一个泛型工具类型,可以获取函数类型的返回值的类型

思路

image.png

得到类型

src\store\index.ts

 type Fn=typeof store.getState
 export type RootState=ReturnType<Fn>

获取类型

src\App.tsx

import { RootState } from './store'
const todos=useSelector((state:RootState)=>state.todos)

6.删除事件

redux

src\store\reducers\todos.ts

export default function todos(state=initState,action:any){
  console.log(action);
  if(action.type==='DEL_TODO'){
    return state.filter(it=>it.id!== action.payload)
  }

声明

app

import {useSelector,useDispatch} from 'react-redux' 
const dispatch=useDispatch()
 const del=(id:number)=>{
   console.log(id);
   dispatch({type:'DEL_TODO',payload:id})
 }

使用

app

    <ul>
      {
        todos.map(item=>(<li key={item.id}>{item.name}
        <button onClick={()=>del(item.id)}>删除</button>
        </li>))
      }
    </ul>

优化

app

 const del=(id:number)=>{
   console.log(id);
   dispatch(delTodo(id))
 }

src\store\actions\delTodo.ts

export const delTodo = (id:number)=>{
  return {
    type:'DEL_TODO',
    payload:id
  }
}

7.优化redux

src\store\actions\index.ts

export type ActionType = {
  type:'DEL_TODO',
  id:number
} 
export const delTodo=(id:number)=>{
  return {
    type:'DEL_TODO',
    id
  }
}

src\store\reducers\todos.ts

import { ActionType } from "../actions";
const initState:TodoItem[]=[
  {
    id:1,
    name:'学习',
    isDone:false
  },
  {
    id:2,
    name:'玩',
    isDone:false
  },
  {
    id:3,
    name:'睡觉',
    isDone:false
  }
] 
export type TodoItem={
  id:number,
  name:string,
  isDone:boolean
}
export default function todos(state:TodoItem[]=initState,action:ActionType):TodoItem[]{
  console.log(action);
  if(action.type==='DEL_TODO'){
    return state.filter(it=>it.id!== action.id)
  }
  
  return state
}

8. 添加事件

app

键盘按下

    if(e.keyCode===13){
   if(e.key==='Enter'){
    if(e.code==='Enter'){

action异步事件注册

src\store\actions\index.ts

export type ActionType = {
  type:'DEL_TODO',
  id:number
} | {
  type:'ADD_TODO',
    name:string
}
export const addTodo=(name:string)=>{
  console.log(name,'name');
  return {
    type:'ADD_TODO',
    name
  }
}

reducer

src\store\reducers\todos.ts

export default function todos(state:TodoItem[]=initState,action:ActionType):TodoItem[]{
  console.log(action);
  if(action.type==='DEL_TODO'){
    return state.filter(it=>it.id!== action.id)
  }else if(action.type==='ADD_TODO'){
    console.log(action);
    
    return [...state,{name:action.name,id:Date.now(),isDone:false}]
  }
  
  return state
}

事件注册

 const add=(e:React.KeyboardEvent<HTMLInputElement>)=>{
   if(e.key==='Enter'){
     console.log(name,'name');
  dispatch(addTodo(name))    
  setName('')
   }

事件绑定

方法1

 <input onKeyUp={add} value={name} onChange={(e)=>setName(e.target.value) }></input>

方法2

<input onKeyUp={(e)=>add(e)} value={name} onChange={(e)=>setName(e.target.value) }></input>

9.点击样式改变

src\store\actions\index.ts

export const changeStateTodo=(id:number,newIsDone:boolean):ActionType=>{
  console.log(id,newIsDone);
  return {
    type:'CHANG_TODO',
    payload:{
      id,
      newIsDone
    } 
  }
}

reducer

src\store\reducers\todos.ts

else if(action.type==='CHANG_TODO'){ 
    console.log(action);
   return state.map(item=>{
  if(item.id===action.payload.id){
    return {...item,isDone:action.payload.newIsDone}
  }else{
    return {...item}
  }
    })

app

事件注册

const changeTodo=(id:number,flag:boolean)=>{
  dispatch(changeStateTodo(id,flag))
}

事件绑定

    <ul>
      <input onKeyUp={(e)=>add(e)} value={name} onChange={(e)=>setName(e.target.value) }></input>
      {
        todos.map(item=>(<li className={item.isDone?'completed':''} key={item.id}> 
        <span onClick={()=>changeTodo(item.id,!item.isDone)}>{item.name}</span> 
        <button onClick={()=>del(item.id)}>删除</button>
        </li>))
      }
    </ul>

10. 初始化数据

设置action异步

src\store\actions\index.ts

import {ActionType} from './actions'
import { ThunkAction } from "redux-thunk"
import axios from "axios"
// thunk类型的变更,使用了thunk之后,返回的Action类型不再是对象,而是函数类型的Action,因此需要修改Action的类型。thunkAction类型的使用
// 参数1:RetrunType 用于指定函数的返回值类型void
// 参数2:指定RootState的类型
// 参数3:指定额外的参数类型,一般为unkonwn或者any
// 参数4:用于指定dispatch的Action类型
export const initTodo=():ThunkAction<void,RootState,unknown,ActionType>=>{
  return async (dispatch)=>{
    const res=await axios.get('####')
    console.log(res);
    dispatch({
      type:'INT_TODO',
      data:res.data.data
    })
  }
}

触发

app

useEffect(()=>{
 dispatch<any>(initTodo())
},[dispatch])

优化

src\store\index.ts

import {ActionType} from './actions'
import { ThunkAction } from "redux-thunk"
export type RootThunkAction=ThunkAction<void,RootState,unknown,ActionType>

src\store\actions\index.ts

import axios from "axios"
import {RootThunkAction} from '../index'
import { TodoItem } from "../reducers/todos"
export type ActionType = {
  type:'DEL_TODO',
  id:number
} | {
  type:'ADD_TODO',
    name:string
} | {
  type:'INT_TODO',
  data:TodoItem[]
}
export const initTodo=():RootThunkAction=>{
  return async (dispatch)=>{
    const res=await axios.get('####')
    console.log(res);
    dispatch({
      type:'INT_TODO',
      data:res.data.data
    })
  }
}

效果展示

image.png

11.注意事项

1.在使用action进行异步操作时,需要使用useDispatch进行相应操作

2.当使用dispatch对action进行异步时,action发axios请求时有的会出现这个问题

image.png

此时我们仅需再dispatch后加< any >类型即可

3.注意:出现问题时,如果代码在别人那里没有问题或你认为自己没有问题就需要注意是不是包的版本出了问题

例如:redux-thunk版本不对就会导致即使加了RootThunkAction类型下面type也不会有提示

自己感受一下4年不动,一动就是大版本更新

image.png