React中通过Context实现状态管理 --typescript

项目中使用context的原因

传递 props 是将数据通过 UI 树显式传递到使用它的组件的好方法。

但是当你需要在组件树中深层传递参数以及需要在组件间复用相同的参数时,传递 props 就会变得很麻烦。最近的根节点父组件可能离需要数据的组件很远,状态提升 到太高的层级会导致 “逐层传递 props” 的情况。
在这里插入图片描述
如何组件过多的话(成百上千个组件的话)一层一层往下传递的话,就会变得很复杂而且不容易维护,所以通过Context 让父组件可以为它下面的整个组件树提供数据。

Context的实现

  1. 创建Context对象
    首先,需要创建一个Context对象,可以通过React.createContext来完成。Context对象可以包含一个Provider组件和一个Consumer组件,但通常只使用Provider。
  2. 提供Context的值
    使用<MyContext.Provider>组件来提供Context的值,它的value属性传递给后代组件。
  3. 在消费组件中使用Context
    通过React.useContext()进行调用实现
import {createContext, useContext} from 'react'
interface contextType  {
    name: string,
    value: string,
  }
const ctx = createContext<contextType | null>(null)
 const [name, setName] = useState<string>('张三');
  const [value, setValue] = useState<string>('1234');
  const contextValue:contextType = {name, value} 
<ctx.provider value={contextValue}>
    子组件
</ctx.provider>

//子组件的调用
import {useContext} from 'react'
  const useGetData = () => {
     const value = useContext(ctx)
     if(!value) throw new Error('')
     return value
  }
  const value = useGetData()
  console.log(ctx.name)
  console.log(ctx.value)
}

注意点

  1. 你在创建context对象的使用需要指明你需要传递数据的类型
  2. 创建对象的时候,你如果没有一个合理的默认值时, 可以设置为null ,不过你在获取数据的时候需要添加判断
  3. 传递的属性需要包裹在value里面,

Context结合useReducer扩展应用

Context进行数据传递, 而useReducer通过这个钩子实现数据状态的修改

下面展示所用的数据类型

export interface State {
   id: number;
   text: string;
   done: boolean;
 };
 
export type CounterAction =
   | { type: "added" , id: State['id'], text: State['text'] }
   | { type: "changed"; task: State }
   | { type: "deleted"; id: State['id'] }
   

State你所声明的变量的类型, CounterAction表示可以 dispatch 至 reducer 的不同 action

如何使用Reducer

  1. 定义一个reducer函数(根据不同的action返回不同的新状态)
  2. 在组件中调用useReducer,并传入reducer函数和初始值
  3. 事件发生时,通过dispatch函数分配一个action对象(通过reducer要返回那个新状态并渲染UI)
//1.创建reducer
 const reducer = (tasks: State[], action: CounterAction) =>{
    switch (action.type) {
      case 'added':
        return [
          ...tasks,
          {
          id: action.id,
          text: action.text,
          done: false
          } ]
      case 'changed': {
        return tasks.map(t => {
              if (t.id === action.task.id) {
                return action.task;
              } else {
                return t;
              }
            });
        }
      case 'deleted': {
         return tasks.filter(t => t.id !== action.id);
          }
        }
  }
  //2.调用useReducer
 const initialState: state[] =  [
    { id: 0, text: 'Learn React', done: true },
    { id: 1, text: 'Learn Redux', done: false },
    { id: 2, text: 'Learn TypeScript', done: false },
  ]
 const [tasks, dispatch] = useReducer(reducer, initialState);  
  //3.dispactch分配状态
  //比如下面这种写法
  dispatch({type:"added", id: "你设置的id", text: "你获得的text"})

使用ts的注意点如下

  • interface State 描述了 reducer state 的类型。
  • type CounterAction 描述了可以 dispatch 至 reducer 的不同 action。
  • const initialState: State 为初始 state 提供类型,并且也将成为 useReducer 默认使用的类型。
  • reducer(state: State[], action: CounterAction): State[] 设置了 reducer 函数参数和返回值的类型

如何和context结合使用 完整代码如下

const App: React.FC = () => {
  // 创建上下文对象

  const reducer = (tasks: State[], action: CounterAction) =>{
    switch (action.type) {
      case 'added':
        return [
          ...tasks,
          {
          id: action.id,
          text: action.text,
          done: false
          } ]
      case 'changed': {
        return tasks.map(t => {
              if (t.id === action.task.id) {
                return action.task;
              } else {
                return t;
              }
            });
        }
      case 'deleted': {
         return tasks.filter(t => t.id !== action.id);
          }
        }
  }
  const [tasks, dispatch] = useReducer(reducer, [
    { id: 0, text: 'Learn React', done: true },
    { id: 1, text: 'Learn Redux', done: false },
    { id: 2, text: 'Learn TypeScript', done: false },
  ]);
  //常见context上下文对象
  //上面已经讲过创建可以赋值为空
  const TaskContext = createContext<State[] | null>(null)
  const TaskDispatchContext = createContext<Dispatch<CounterAction> | null>(null)
  return (
    <>
     <TasksContext.Provider value={tasks}>
      <TasksDispatchContext.Provider value={dispatch}>
        子组件
      </TasksDispatchContext.Provider>
     </TasksContext.Provider>
    </>
  );
}

//子组件的实现
import { useContext, useState } from "react"
import { State } from "@/store/type/useReducer"
import { TasksContext, TasksDispatchContext } from "@/store/tasksContext/tasksContext"
const StateManage:React.FC = () => {

    const useGetTasks = () => {
        const tasks = useContext(TasksContext)
        if(!tasks) throw new Error('useGetTasks必须放在TasksContext.Provider中')
        return tasks
    }
    const useGetDispatch = () => {
        const dispatch = useContext(TasksDispatchContext)
        if(!dispatch) throw new Error('useGetTasksDispatch必须放在TasksContext.Provider中')
        return dispatch
    }
    const dispatch = useGetDispatch();
    const tasks = useGetTasks()

    // if(!tasks) return null
    const [id, setId] = useState(tasks[tasks.length - 1].id + 1)

    const [text, setText] = useState('')
    const addTask = () => {
        dispatch({type: 'added', id, text})
        setId(id + 1)
        setText('')
    }
    // 删除数据
    const deleteTask = (id: number) => {
        dispatch({type: 'deleted', id})
    }
    // 修改数据
    const changeTask = (value: State) => {
        dispatch({type: 'changed', task: {id: value.id, text: value.text, done: true}})
    }
    return (
        <div>
            stateManage
            <ul>
                {tasks.map(item => {
                    return <li key = {item.id} style={{color: item.done ? 'black' : 'red'}}>
                        <p style={{display: "inline-block"}}  onClick={() => deleteTask(item.id)}>{item.text}</p>
                        <button onClick={() => changeTask(item)} style={{marginLeft: '30px'}}>修改task</button> 
                        </li>
                })}
            </ul>

            {/* 添加状态 */}
            <input type="text" value={text} onChange={(e) => setText(e.target.value)} />

            <button onClick={addTask}>添加数据到tasks中</button>
        </div>
    )
}
export default StateManage

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React Hook是React 16.8版本引入的一种新的特性,它可以让你在无需编写类组件的情况下使用状态和其他React特性。TypeScript是一种静态类型检查的JavaScript超集,可以帮助我们在开发过程发现并修复潜在的错误。 要深入学习React Hook和TypeScript技术栈,你可以按照以下步骤进行: 1. 学习React基础知识:在学习React Hook之前,确保你对React的基础知识有一定的了解。理解React组件、生命周期、状态管理等概念是很重要的。 2. 学习TypeScript基础知识:如果你还不熟悉TypeScript,可以先学习一些基础知识,比如类型注解、接口、泛型等。掌握这些概念可以帮助你更好地使用TypeScript进行开发。 3. 学习React Hook:阅读React官方文档关于React Hook的内容,并尝试编写一些简单的Hook。掌握useState、useEffect、useContext等常用的Hook函数,并理解它们的使用方法和原理。 4. 使用TypeScript编写React Hook:在掌握了React Hook的基本知识后,你可以开始使用TypeScript编写React Hook。使用TypeScript可以为你的代码提供类型检查和智能提示,减少潜在的错误。 5. 实践项目:选择一个小型的项目或者练习,使用React Hook和TypeScript进行开发。通过实践项目可以帮助你更好地理解和掌握这两个技术栈。 6. 深入学习进阶内容:一旦你对React Hook和TypeScript有了基本的了解,你可以进一步学习一些进阶内容,比如自定义Hook、使用第三方库、使用Context API等。 记住,深入学习任何技术栈都需要时间和实践。通过不断地阅读文档、编写代码和解决问题,你会逐渐掌握React Hook和TypeScript技术栈。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值