React Hooks TypeScript 事件和状态类型

Posted

技术标签:

【中文标题】React Hooks TypeScript 事件和状态类型【英文标题】:React Hooks TypeScript event and state types 【发布时间】:2020-05-25 00:31:48 【问题描述】:

React.js 的状态和事件有哪些类型?

在下面的代码中,我只能通过使用type: any 使其工作,但这只是一个 hack。我怎样才能为他们使用正确的类型?

在我的自定义钩子中:

如果我使用function useFormFields(initialState: object),我会得到:

// value=inputs.item error:
Property 'item' does not exist on type 'object'.ts(2339)
// onChange function error:
(JSX attribute) onChange: object
No overload matches this call.

如果我使用function(event: React.FormEvent)(这是真的),我有这个错误:

Property 'id' does not exist on type 'EventTarget'.ts(2339)

如果我使用function(event: object),我有这个错误:

Property 'target' does not exist on type 'object'.ts(2339)

这很奇怪,因为下面我使用 const handleSubmitItem = (event: React.FormEvent) 并且它有效。

我找到的答案(如this one)对我不起作用,因为Property 'id' does not exist on type 'EventTarget'

import React, useState from 'react';
import TextField from '@material-ui/core/TextField';
import IconButton from '@material-ui/core/IconButton';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';

/**
 * Custom hooks for input fields.
 * @param initialState initialState for Input Fields
 */
function useFormFields(initialState: any) 
    const [inputs, setValues] = useState(initialState);

    return [
        inputs,
        function(event: any) 
            setValues(
                ...inputs,
                [event.target.id]: event.target.value
            );
        
    ];


export default function FormPropsTextFields() 
    const [inputs, handleInputChange] = useFormFields(
        item: '',
        quantity: '',
        store: ''
    );

    const handleSubmitItem = (event: React.FormEvent) => 
        event.preventDefault();
        console.log(inputs);
    ;

    return (
        <form 
            className=classes.root 
            noValidate autoComplete="off"
            onSubmit=handleSubmitItem
        >
            <div>
                <TextField 
                    required id="item" 
                    label="Item" 
                    value=inputs.item
                    onChange=handleInputChange
                />
                <TextField
                    id="quantity"
                    label="Quantity"
                    type="number"
                    value=inputs.quantity
                    onChange=handleInputChange
                    InputLabelProps=
                        shrink: true,
                    
                />
                <TextField 
                    id="store" 
                    label="Store" 
                    type="search"
                    value=inputs.store
                    onChange=handleInputChange
                />
                <IconButton 
                    type="submit"
                    color="primary" 
                    aria-label="add to shopping cart"
                >
                    <AddShoppingCartIcon />
                </IconButton>
            </div>
        </form>
    );


【问题讨论】:

【参考方案1】:

我对您找到的解决方案进行了一些更正。 希望对您有所帮助!

import React, useState from 'react';
import TextField from '@material-ui/core/TextField';
import IconButton from '@material-ui/core/IconButton';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';

/**
 * Custom hooks for input fields.
 * @param initialState initialState for Input Fields
 */

export interface MyModel 
    item: string
    quantity: string
    store: string


function useFormFields<T>(initialState: T): [T, (event: React.ChangeEvent<htmlTextAreaElement | HTMLInputElement>) => void] 
    const [inputs, setValues] = useState<T>(initialState);

    return [
        inputs,
        function (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) 
            setValues(
                ...inputs,
                [event.target.id]: event.target.value
            );
        
    ];


export default function FormPropsTextFields() 
    const [inputs, handleInputChange] = useFormFields<MyModel>(
        item: '',
        quantity: '',
        store: ''
    );

    const handleSubmitItem = (event: React.FormEvent) => 
        event.preventDefault();
        console.log(inputs);
    ;

    return (
        <form 
            className=classes.root 
            noValidate autoComplete="off"
            onSubmit=handleSubmitItem
        >
            <div>
                <TextField 
                    required id="item" 
                    label="Item" 
                    value=inputs.item
                    onChange=handleInputChange
                />
                <TextField
                    id="quantity"
                    label="Quantity"
                    type="number"
                    value=inputs.quantity
                    onChange=handleInputChange
                    InputLabelProps=
                        shrink: true,
                    
                />
                <TextField 
                    id="store" 
                    label="Store" 
                    type="search"
                    value=inputs.store
                    onChange=handleInputChange
                />
                <IconButton 
                    type="submit"
                    color="primary" 
                    aria-label="add to shopping cart"
                >
                    <AddShoppingCartIcon />
                </IconButton>
            </div>
        </form>
    );

【讨论】:

谢谢@nightElf,让我试试然后回复你。【参考方案2】:

由于每个组件可能不同,您需要自己定义 state 和 props 类型。为 react 定义了一些基本类型(例如,因为每个组件都可能有 children),但正如我所说,您需要定义自己的类型。

功能组件的示例:

const App: React.FC< message: string > = ( message ) => (
  <div>message</div>
);

上面的例子也可以这样写:

type MyType =  message: string 
const App: React.FC<MyType> = ( message ) => (
  <div>message</div>
);

在此处进一步阅读:

https://github.com/typescript-cheatsheets/react-typescript-cheatsheet#section-2-getting-started

【讨论】:

谢谢@messerbill,让我试试,然后回复你。【参考方案3】:

将军们!答案!

希望对你有帮助!


import IconButton from '@material-ui/core/IconButton';
import TextField from '@material-ui/core/TextField';
import AddShoppingCartIcon from '@material-ui/icons/AddShoppingCart';
import React,  useState  from 'react';

export interface MyModel 
    item: string;
    quantity: string;
    store: string;
 

/**
 * Custom hooks for input fields.
 * @param initialState initialState for Input Fields
 **/
function useFormFields<T>(initialState: T) 
    const [inputs, setValues] = useState(initialState);

    return [
        inputs,
        function(event: React.FormEvent) 
            const name, value = event.currentTarget;
            setValues(
                ...inputs,
                [name]: value
            );
        
    ];


export default function FormPropsTextFields() 
    const [inputs, handleInputChange] = useFormFields<MyModel>(
        item: '',
        quantity: '',
        store: '',
    );

    const handleSubmitItem = (event: React.MouseEvent<HTMLButtonElement>) => 
        event.preventDefault();
        /***
           make sure to have whatever attribute you want in the "html tag"
        */
        const  name, value  = event.currentTarget;
        console.log(inputs);
    ;

    return (
        <form
            className=classes.root
            noValidate autoComplete="off"
        >
            <div>
                <TextField
                    required id="item"
                    label="Item"
                    name="Item"
                    value=inputs.item
                    onChange=handleInputChange
                />
                <TextField
                    id="quantity"
                    label="Quantity"
                    name="Quantity"
                    type="number"
                    value=inputs.quantity
                    onChange=handleInputChange
                    InputLabelProps=
                        shrink: true,
                    
                />
                <TextField
                    id="store"
                    label="Store"
                    name="Store"
                    type="search"
                    value=inputs.store
                    onChange=handleInputChange
                />
                <IconButton
                    type="button"
                    color="primary"
                    aria-label="add to shopping cart"
                    onClick=handleSubmitItem
                >
                    <AddShoppingCartIcon />
                </IconButton>
            </div>
        </form>
    );


【讨论】:

谢谢@Emesto,让我试试然后回复你。 抱歉,差距过大。你的答案返回这些错误:property 'name' does not exist on type 'EventTarget &amp; Element'. 如果我保留[event.target.id]: event.target.value,它会返回:Property 'id' does not exist on type 'EventTarget'.

以上是关于React Hooks TypeScript 事件和状态类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React with Typescript 中使用和指定通用 Hooks?

基于 React hooks + Typescript + Cesium 的 三维 webgis 实战系列教程

React Typescript with hooks:最大更新深度超出错误

状态上不存在属性 - 使用带有 TypeScript 的 React Router Hooks

React Hooks Typescript 开发的一款 H5 移动端 组件库

React Hooks 和 TypeScript Fetching API:对象可能为“空”