【问题标题】:React and Typescript, which types for Axios response?React 和 Typescript,Axios 响应的类型有哪些?
【发布时间】:2020-09-24 19:06:22
【问题描述】:

我正在尝试从返回以下内容的 API 中呈现一个简单的用户列表:

[{"UserID":2,"FirstName":"User2"},{"UserID":1,"FirstName":"User1"}]

我不完全了解如何处理带有类型的 Axios 响应。打字稿错误是

Type '{} | { id: number; firstName: string; }' is not assignable to type 'IntrinsicAttributes & UserListProps & { children?: ReactNode; }'.
Property 'items' is missing in type '{}' but required in type 'UserListProps'.

来自下面Users.tsx 文件中的<UserList /> 元素。我的User接口错了吗?

import React, {useEffect, useState, Fragment } from 'react';
import UserList from './UserList';
import axios, {AxiosResponse} from 'axios';

interface User {
    id: number;
    firstName: string;
}

const Users: React.FC = (props) => {
    const [users, setUserList] = useState<User>();

    useEffect(() => {
        // Use [] as second argument in useEffect for not rendering each time
        axios.get('http://localhost:8080/admin/users')
        .then((response: AxiosResponse) => {
            console.log(response.data);
            setUserList( response.data );
        });
    }, []);

    return (
        <Fragment>
            <UserList {...users} />
        </Fragment>

    );
};
export default Users;

下面是我的UserList.tsx

import React, {Fragment } from 'react';

interface UserListProps {
    items: {id: number, firstName: string}[];
};

const UserList: React.FC<UserListProps> = (props) => {
    return (
        <Fragment>
            <ul>
            {props.items.map(user => (
                <li key={user.id}>
                    <span>{user.firstName}</span>
                    {/* not call delete function, just point to it
                    // set this to null in bind() */}
                </li>
            ))}
            </ul>
        </Fragment>
    );
};

export default UserList;

【问题讨论】:

    标签: reactjs typescript axios


    【解决方案1】:

    generic get method defined in axios/index.d.ts

    get<T = never, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig<T>): Promise<R>;
    

    例子

    interface User {
        id: number;
        firstName: string;
    }
    
    
    axios.get<User[]>('http://localhost:8080/admin/users')
            .then(response => {
                console.log(response.data);
                setUserList( response.data );
            });
    

    --编辑

    我认为您将列表以错误的方式传递给子组件。

    const [users, setUserList] = useState<User[]>([]);
    
    <UserList items={users} />
    
    interface UserListProps {
        items: User[];
    };
    
    const UserList: React.FC<UserListProps> = ({items}) => {
        return (
            <Fragment>
                <ul>
                {items.map(user => (
                    <li key={user.id}>
                        <span>{user.firstName}</span>
                    </li>
                ))}
                </ul>
            </Fragment>
        );
    };
    

    【讨论】:

    • 谢谢,所以我应该使用axios.get&lt;User&gt; 而不是useState&lt;User&gt;()?如果我尝试这样做,Typescript 会抱怨 useState() 未定义。
    • 更新了答案。起初我以为你只是得到一个对象,但这实际上是一个数组。只需将[] 括号放在几个地方
    • 我认为现在唯一缺少的部分是我如何初始化useState()。我明白了:Argument of type 'User[]' is not assignable to parameter of type 'SetStateAction&lt;undefined&gt;'. Type 'User[]' provides no match for the signature '(prevState: undefined): undefined'.ts(2345)
    • 你必须用空数组初始化useState([])。否则,您必须扩展类型 useState&lt;User[] | undefined&gt;() 添加检查变量是否在子组件中未定义并对其进行处理
    【解决方案2】:

    如果您不希望 axios 推断值 response 的类型,则需要在调用 axios.get 时提供类型参数。

    当您useState 创建用户数组时,您传递的类型参数不正确。

    正确的方法

    interface User {
      id: number;
      firstName: string;
    }
    
    // initialized as an empty array
    const [users, setUserList] = useState<User[]>([]); // users will be an array of users
    

    例如,

    import React, {useEffect, useState, Fragment } from 'react';
    import UserList from './UserList';
    import axios from 'axios';
    
    interface User {
      id: number;
      firstName: string;
    }
    
    // you can export the type TUserList to use as -
    // props type in your `UserList` component
    export type TUserList = User[]
    
    const Users: React.FC = (props) => {
       // you can also use User[] as type argument
        const [users, setUserList] = useState<TUserList>();
    
        useEffect(() => {
            // Use [] as second argument in useEffect for not rendering each time
            axios.get<TUserList>('http://localhost:8080/admin/users')
            .then((response) => {
                console.log(response.data);
                setUserList( response.data );
            });
        }, []);
    
        return (
            <Fragment>
                <UserList {...users} />
            </Fragment>
    
        );
    };
    export default Users;
    

    如果您选择导出类型type TUserList = User[],您可以在UserList 组件中使用它作为道具类型。例如,

    import React, {Fragment } from 'react';
    import { TUserList } from './Users';
    
    interface UserListProps {
        items: TUserList // don't have to redeclare the object again
    };
    
    const UserList: React.FC<UserListProps> = (props) => {
        return (
            <Fragment>
                <ul>
                {props.items.map(user => (
                    <li key={user.id}>
                        <span>{user.firstName}</span>
                        {/* not call delete function, just point to it
                        // set this to null in bind() */}
                    </li>
                ))}
                </ul>
            </Fragment>
        );
    };
    
    export default UserList;
    

    【讨论】:

    • 关于导出TUserList 类型非常好,非常感谢您的出色回答:)
    • 我很高兴它有帮助。
    猜你喜欢
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 2021-02-09
    • 2021-02-11
    • 2021-07-26
    • 1970-01-01
    • 2020-08-10
    • 2021-03-30
    相关资源
    最近更新 更多