在React中使用TypeScript(2)

553 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。 大家好,我是大帅子,今天我们接着昨天的来介绍 todos案例, 我们直接开始,这边给大家附上仓库地址 , gitee.com/dashuaizi/t…


修改状态

1.我们直接开始干,我们先尝试修改状态,先定义一个按钮,然后在把状态渲染出来

 {todos.map(item => <li key={item.id} style={{ listStyle: 'none' }}>
          {item.name} {item.isDone ? '已完成' : '未完成'}
          <button onClick={() => update(item.id)}>给我变</button>
    </li>)}
 
  1. 因为我们这时要用到dispatch了,但是我们发现用原来的办法会报错,我这边有解决方案
  const dispatch = useDispatch<Dispatch<{ type: string, payload: any }>>()
  
    // 改变状态
  const update = (id: number) => {
    // console.log(id);
    dispatch(updateState(id))
  }
  1. 然后我们在 /store/action/todos 中写处理函数,先定义类型,下面直接使用
type TodoAction =
  {
    type: 'UPDATE_STATE' // 字面量类型
    payload: number
  }


export const updateState = (id: number): TodoAction => {
  return {
    type: 'UPDATE_STATE',
    payload: id
  }
}

4.最后一步我们只需要在/store/reducer/todos.ts中写入改变状态的代码,一样我们需要先定义好状态

export type TodoType = {
  id: number
  name: string
  isDone: boolean
}

//在那边传值过来这边直接,做判断
export default function todos(state = initValue, action: any): TodoType[] {
  // 修改状态
  const id = action.payload

  if (action.type === 'UPDATE_STATE') {
    return state.map(item => {
      if (item.id === id) {
        return { ...item, isDone: !item.isDone }
      } else {
        return { ...item }
      }
    })
  }

  return state
}

useRef的泛型参数

useRef 接收一个泛型参数,源码如下

/**
 * `useRef` returns a mutable ref object whose `.current` property is initialized to the passed argument
 * (`initialValue`). The returned object will persist for the full lifetime of the component.
 *
 * Note that `useRef()` is useful for more than the `ref` attribute. It’s handy for keeping any mutable
 * value around similar to how you’d use instance fields in classes.
 *
 * @version 16.8.0
 * @see https://reactjs.org/docs/hooks-reference.html#useref
 */
function useRef<T>(initialValue: T): MutableRefObject<T>;
    
interface MutableRefObject<T> {
    current: T;
}

useRef的泛型参数用于指定current属性的值的类型

解决方法

使用useRef操作DOM,需要明确指定所操作的DOM的具体的类型,否则current属性会是null

正确语法:

const inputRef = useRef<HTMLInputElement>(null)

添加

  1. 设置一个添加按钮,跟一个输入框 ,然后获取表单的值
  <input type="text" onKeyUp={keyUP} ref={refInput} />
  <button onClick={add} >添加</button>
  
  // 添加
  const add = (e: any) => {
    console.log(e);
    // 这边作为非空断言 , 不然会报错
    if (refInput.current) {
      // console.log(refInput.current.value);
      dispatch(addTodos(refInput.current.value))
    }
  }  
  1. 我们在进去 action/todos.ts中进行操作
type TodoAction =
  {
    type: 'add_TODO'
    payload: TodoType
  }


export const addTodos = (name: string): TodoAction => {
  // console.log(data, 333);
  return {
    type: 'add_TODO',
    payload: {
      id: Date.now(),
      name,
      isDone: false
    }
  }
}
  1. 我们因为不用新加模块,如果新加模块的话,我们就要在/store/reducers/index.ts中添加模块
import { combineReducers } from 'redux'
import todos from './todos'
import channel from './channel'

const rootReducer = combineReducers({
  todos, // 新加模块
})

export default rootReducer
  1. 最后我们要在/store/reducer/todos.ts中间进行最后的代码
export type TodoType = {
  id: number
  name: string
  isDone: boolean
}


const initValue: TodoType[] = [
  {
    id: 1,
    name: '吃饭',
    isDone: false,
  }
]

export default function todos(state = initValue, action: any): TodoType[] {

  // 添加
  else if (action.type === 'add_TODO') {
    console.log(action.payload, 2323423);

    return [...state, action.payload]
  }

  return state
}
  1. 我们可以拓展一下,写一个按下键盘松开事件,可以检测我们按下的是哪个键,enter键的发送信息
 <input type="text" onKeyUp={keyUP} ref={refInput} />
 
   // 回车事件 这个东西大家可以直接复制,以后直接用就行了,改一下事件名的事
  const keyUP = (e: any) => {
    if (e.keyCode === 13 && refInput.current) {
      dispatch(addTodos(refInput.current.value))
    }
  }

最后我们来讲删除,

与其说讲,我更想让你们自己尝试一下,大家可以先试试怎么做,但是步骤我还是放在下面

1.我们先设置删除的按钮,再写一个处理事件

    <ul>
        {todos.map(item => <li key={item.id} style={{ listStyle: 'none' }}>
          <button onClick={() => del(item.id)}>删除</button>
        </li>)}
    </ul>

 // 删除
  const del = (id: number) => {
    dispatch(delState(id))
  }

2. 我们在 /store/action/todos 定义类型跟处理事件

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

3. 我们需要在 /storereducers/todos.ts 中间做最后的处理

export default function todos(state: TodoType[] = initValue, action: any): TodoType[] {

  // 删除
  else if (action.type === 'DEL_TODO') {
    return state.filter(item => item.id !== id)
  }

  return state
}

好了,到此我们的小案例就结束了,不知道大家有没有学会没有,以上是我自己的理解,讲的不好, 欢迎留言我这边一定会第一时间给大家解答,喜欢的可以点赞收藏,
🐣---->🦅        还需努力!大家一起进步啊!!!!