如何输入自定义钩子 useStateWithCallback React TypeScript

2024-01-06

我在输入以下自定义 React 时遇到问题hook,我是 TypeScript 新手,这引起了一些混乱。

const useStateCallback = (initialState: any) => {
  const [state, setState] = useReducer<Reducer<any, any>>((state, newState) => ({ ...state, ...newState }), initialState)
  const cbRef = useRef(null)

  const setStateCallback = (state, cb) => {
    cbRef.current = cb
    setState(state)
  }

  useEffect(() => {
    if (cbRef.current) {
      cbRef.current(state)
      cbRef.current = null
    }
  }, [state])

  return [state, setStateCallback]
}

我应该使用any在这里,如果是的话我该如何使用any适当地? 既然这是通用函数并且可以在任何地方使用,那么我如何正确输入它呢?

我在我的示例中添加了一些尝试,并且,正如您所看到的,我停止了,因为从我的角度来看,它最终会一无所获,但any types.


首先,你需要做这个useStateCallback接受代表您的状态的通用参数。您将经常使用该参数。我们称之为S对于状态。

function useStateCallback<S>(initialState: S) { ... }

接下来是减速机。看来您只需要一个接受Partial https://www.typescriptlang.org/docs/handbook/utility-types.html#partialt of S并入国家。所以对于两个通用参数Reducer we use S对于国家和Partial<S>为了行动。

const [state, setState] = useReducer<Reducer<S, Partial<S>>>(
  (state, newState) => ({ ...state, ...newState }),
  // state is implicitly typed as: S
  // newState is implicitly typed as: Partial<S>

  initialState
)

或者,您可以输入化简器函数的参数,然后将推断出这些类型,这看起来更干净,恕我直言。

const [state, setState] = useReducer(
  (state: S, newState: Partial<S>) => ({ ...state, ...newState }),
  initialState
)

为了创建引用,我们需要给它一个回调函数的类型,并与null因为它可能并不总是包含值:

const cbRef = useRef<((state: S) => void) | null>(null)

for setStateCallback,我们需要接受Partial<S>与完整状态合并,以及将完整状态作为唯一参数的回调:

function setStateCallback(state: Partial<S>, cb: (state: S) => void) {
  cbRef.current = cb
  setState(state)
}

你的效果应该很好。

最后要做的是将您的退货更改为:

return [state, setStateCallback] as const

这是必需的,因为默认情况下打字稿将其视为数组,但您希望它是元组。而不是数组(S | Callback)[]你希望它是一个恰好有两个类型元素的元组[S, Callback]。追加as const到数组告诉打字稿将数组视为常量并将这些类型锁定到正确的位置。

将所有这些放在一起,您将得到:

import React, { useReducer, useRef, useEffect, Reducer } from 'react'

function useStateCallback<S>(initialState: S) {
  const [state, setState] = useReducer<Reducer<S, Partial<S>>>(
    (state, newState) => ({ ...state, ...newState }),
    initialState
  )
  const cbRef = useRef<((state: S) => void) | null>(null)

  function setStateCallback(state: Partial<S>, cb: (state: S) => void) {
    cbRef.current = cb
    setState(state)
  }

  useEffect(() => {
    if (cbRef.current) {
      cbRef.current(state)
      cbRef.current = null
    }
  }, [state])

  return [state, setStateCallback] as const
}

// Type safe usage
function Component() {
  const [state, setStateCallback] = useStateCallback({ foo: 'bar' })

  console.log(state.foo)

  setStateCallback({ foo: 'baz' }, newState => {
    console.log(newState.foo)
  })

  return <div>{state.foo}</div>
}

操场 https://www.staging-typescript.org/play?#code/JYWwDg9gTgLgBAJQKYEMDGMA0cDecCuAzksgCb5pJTZElIBmNxAovfUhtmRVXAL5x6UCCDgByKKgxiAUDPr4AdhmARFBYgGUYKGEgDCKADZGARugDWAHk0A+ABTBFwGMGPbdSAFxxNASlwZODgguDQ1QngAbUjPbGIYDz0AXTgAXg06ckooe1Dg+1i9H01sRSQAdyTvOAAFFFg3IxtbALTbOHs8ADpeoqRsXu7yqp09fj9MfLgnFybq0L9Q8MVIsNNkenTMzat7QrGa-3SOgDcIYFIAgB84RXwTB3uTJdCFZVc1OATqwxNzNAWA6eHz1RrGFrYNCmHzA4q+NpnC5XQLBYLQzbdND4KCSRTwDLQ6Y-Q5wpBLYJ8OTBWisdgYfaI1Fo4BbewYhhYnF4mABHDTdEbTnY3FIfFkilowWYkU87bPIzTKmU7AxQ7JV7BSQwHHqNVxb5IRKHP5mSypFCEMIRGAyKkyAD0DrgABUAJ5gJDfFDsDQoADmSHkShUX30Ikg5XFfOWNrg+r08SNv2MZsBqQytBT-0sXUEEAgPjE5igYgm1OtqwgRiQ3SMEH9ZO69ALmsNxs8poBQLwLcL4nMAC8y3wypVqidmeiItXa-XGyNqs3W6E+G3tbq4FZSMBTrYcP1lxA+FYHTu93agA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何输入自定义钩子 useStateWithCallback React TypeScript 的相关文章

随机推荐

  • 为什么使用 Object.create() 和 console.log() 时不显示属性?

    当我使用文字语法创建对象时 将对象打印到控制台会显示该对象foo和p财产 foo foo p 42 console log foo console log foo p Outputs p 42 当我使用 Object create 语法时
  • SWI序言中#=和=:=有什么区别

    What is the difference between and in SWI prolog I have found the definition from SWI prolog but still confused about it
  • php 析构函数在流畅的界面下调用得太早

    我发现 php 析构函数有一个非常奇怪的事情 基本上我有一个数据库管理类 它使用工厂加载适配器来定义应该加载哪个适配器 mysql mysqli等 我只会写下代码中有趣的部分 因为类本身更长 但代码不涉及当前的麻烦 该问题仅发生在 mysq
  • 从 git 中删除但保留在工作目录中

    我添加了一堆要由 git 跟踪的文件 但它们被错误地添加 并提交 它们应该存在于工作目录中 它们是我的 IDE 使用的临时文件 但不被 git 跟踪 我现在已经创建了一个 gitignore 文件并添加了适当的条目 但是将文件从 git 跟
  • KnexJS 迁移及相关种子数据

    我在学习 BookshelfJS KnexJS 从 SequelizeJS 切换 的过程中遇到了将数据导入到通过 KnexJS 中的迁移功能创建的多个表中的问题 有4张桌子 servers operating systems applica
  • 点击特定选项卡即可获取对应的详细信息

    html部分 div class tab content div class tab pane active div class row fluid div class span9 offset1 div div div div
  • 如何从网页访问 Dialogflow V2 API?

    我有一个网页 我想在其中使用对话流聊天机器人 这是一个自定义聊天窗口 因此我不想使用一键集成 我能够访问聊天代理V1 API使用 javascript ajax 通过传递客户端访问令牌在请求标头中 但我不知道该怎么做V2 API 我不清楚对
  • Android内部存储和本地目录中的文件

    Android 为您提供 getDir 我认为这意味着我将拥有 myappspace somedirectory 来在您的应用程序空间中创建一个目录 但是 当 android 给你一个错误时 如果你在 openFileOutput Inpu
  • 使用 Altair 对标准化堆积条形图进行排序

    我正在尝试根据特定顺序对标准化堆积条形图进行排序 我想要按此顺序排序的堆叠条 Order dict Paid work 1 Education 2 Sleep 3 Other unpaid work 4 Housework Shopping
  • SAS数字到字符的转换?

    当我们将数字转换为字符时 我们应该使用如下的数字格式 data test prodID 001 result put prodID 1 run proc print run 我也尝试过使用字符格式 1 而且它也有效 data test pr
  • 为什么我的 React 组件没有随着状态更新而更新?

    我构建了一个地图应用程序 需要在按下按钮后显示 消失一些地图图标 但当我从其父组件传递新的运动属性时 我不知道如何将其设置为重新渲染组件 父加载组件
  • Mysql 中使用 select where 查询区分大小写

    嗨 我正在使用 Java 前端和 Mysql 后端 其实在tbl test包含 name value abc 22 xyz 14 ABC 32 xyZ 4 ABc 4 在java中我尝试检索abc的值于是写了一段代码 ResultSet r
  • pandas 将数据帧转为 3D 数据

    似乎有很多可能性可以将平面表数据转换为 3d 数组 但我不知何故找不到一种有效的方法 假设我有一些带有 columns name type date 的数据价值 当我尝试通过 pivot index name columns type da
  • CSS 截掉输入框的末尾

    老天爷 为什么我的输入框右侧被切掉了 我研究了 chrome 中的填充和边距 但看不出是什么原因造成的 我对此很陌生 但这仍然是一个谜 http jsfiddle net GCt3z 1 http jsfiddle net GCt3z 1
  • DoctrineExtensions 软删除

    我正在使用 Doctrine2 设置 symfony2 并且我想使用 DoctrineExtensions Gedmo 我遵循了每一步 大多数都在工作 但我无法找到需要更改的配置文件 SoftDeleteable 可以工作 https gi
  • hive 版本 0.13.1 中的性能问题

    I use AWS EMR http docs aws amazon com ElasticMapReduce latest DeveloperGuide UsingEMR SupportedHiveVersions html运行我的 Hi
  • SwiftUI 中文本的自定义字体大小

    我认为有一个标签 我想使用系统字体大小为medium 大小为21点 我创建了一个自定义扩展来重新使用创建的字体 extension Font static var primaryButton Font return Font custom
  • 鼠标滚动选中和取消选中 DataGrid 中的复选框

    private void OnChecked object sender RoutedEventArgs e try LAB TEST t new LAB TEST CheckBox chk CheckBox e OriginalSourc
  • 如何使用 Axis WSDL2Java 生成的文件?

    我使用 WSDL2Java 转换器从 WSDL 生成了 Java 文件 但我不知道如何将服务与这些文件一起使用 因为没有示例 我正在实施客户端 关于 Axis2 阅读这些链接 它们包含一些示例 http ws apache org axis
  • 如何输入自定义钩子 useStateWithCallback React TypeScript

    我在输入以下自定义 React 时遇到问题hook 我是 TypeScript 新手 这引起了一些混乱 const useStateCallback initialState any gt const state setState useR