Typescript、React、强类型 useHistory

问题描述 投票:0回答:5

我将 useHistory (react-router-dom) 变量作为参数发送给employee.service,其中我使用带有状态和路径名的“history.push”方法。不幸的是,我似乎无法找出正确的类型。我用过:

History<unknown>
History<Location>

但两人似乎都不明白我所经历的状态。有谁知道如何强输入这个?非常感谢任何帮助!

服务中的create方法:

export const createEmployee = async (body: IEmployee, history: any) => {
    try {
        const employeesResponse = await fetch(`http://localhost:3000/employees`, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify(body),
        });

        if (employeesResponse.status !== 201) {
            const response: IHttpResponse = {
                status: employeesResponse.status,
                error: {message: employeesResponse.statusText},
                data: {content: ''}
            }
            return response
        }

        const employeeResult: IEmployee[] = await employeesResponse.json();
        const response: IHttpResponse = {
            status: employeesResponse.status,
            error: {message: ''},
            data: {content: employeeResult}
        }

        history.push({
            pathname: '/',
            state: { detail: 'reload', response: response },
        });
        
    } catch (error) {
        console.log('error while creating', error);
        const response: IHttpResponse = {
            status: error.status,
            error: {message: error.statusText},
            data: {content: ''}
        }
        return response;
    }
}

使用服务的组件

import React, { useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { Button, Input, Label } from 'reactstrap';
import FormGroup from 'reactstrap/es/FormGroup';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import Select from 'react-select';
import { useHistory } from 'react-router-dom';
import { gendersList, statusList } from '../models/lists/formLists';
import { IOptionType } from '../models/IOptionType';
import { createEmployee } from '../services/employee.service';
import { IEmployee } from './../models/IEmployee';


export const AddEmployeeForm = () => {
const history = useHistory();

const [gender, setGender] = useState<IOptionType>({ label: gendersList[0].label, value: gendersList[0].value });
const [status, setStatus] = useState<IOptionType>({ label: statusList[0].label, value: statusList[0].value });

const validationSchema = yup.object().shape({
    firstname: yup.string().required().min(2),
    lastname: yup.string().required().min(2),
    email: yup.string().email().required(),
    status: yup.object().shape({
        label: yup.string(),
        value: yup.string(),
    }),
    gender: yup.object().shape({
        label: yup.string(),
        value: yup.string(),
    }),
});

const {
    handleSubmit,
    control,
    formState: { errors },
    register,
} = useForm({
    resolver: yupResolver(validationSchema),
});

const handleGenderChange = (option: IOptionType) => {
    setGender({ label: option.label, value: option?.value });
};

const handleStatusChange = (option: IOptionType) => {
    setStatus({ label: option.label, value: option?.value });
};

const onSubmit = async (data: any) => {
    console.log('errors', errors);

    const body: IEmployee = {
        first_name: data.firstname,
        last_name: data.lastname,
        email: data.email,
        gender: gender.value ? gender.value : '',
        status: status.value ? status.value : '',
    };

    console.log('Data', body);

    createEmployee(body, history);
};

return (
    <div className="col-12">
        <form onSubmit={handleSubmit(onSubmit)}>
            <FormGroup>
                <Label for="firstname">First name</Label>
                {errors.firstname && <p className="text-danger error-message">{errors.firstname.message}</p>}
                <Input {...register('firstname')} />
            </FormGroup>

            <FormGroup>
                <Label for="lastname">Last name</Label>
                {errors.lastname && <p className="text-danger error-message">{errors.lastname.message}</p>}
                <Input {...register('lastname')} />
            </FormGroup>

            <FormGroup>
                <Label for="email">Email</Label>
                {errors.email && <p className="text-danger error-message">{errors.email.message}</p>}
                <Input {...register('email')} />
            </FormGroup>

            <FormGroup>
                <Label for="gender">Gender</Label>
                <Controller
                    name="gender"
                    control={control}
                    render={({ field: { onChange, onBlur, value, ref } }) => (
                        <Select
                            options={gendersList}
                            onChange={(value) => handleGenderChange({ value: value?.value, label: value?.label })}
                            onBlur={onBlur}
                            defaultValue={gender}
                            selected={value}
                        />
                    )}
                />
            </FormGroup>

            <FormGroup>
                <Label for="status">Status</Label>
                <Controller
                    name="status"
                    control={control}
                    render={({ field: { onChange, onBlur, value, ref } }) => (
                        <Select
                            options={statusList}
                            onChange={(value) => handleStatusChange({ value: value?.value, label: value?.label })}
                            onBlur={onBlur}
                            value={status}
                            selected={value}
                        />
                    )}
                />
            </FormGroup>

            <Button type="submit">Submit</Button>
        </form>
    </div>
);

};

reactjs typescript
5个回答
2
投票

您可以使用

RouterChildContext
访问
useHistory
类型。

const foo = (history: RouterChildContext['router']['history']) => {
  history.push('/your-path');
}

这来自

react-router
类型声明文件:

// This is the type of the context object that will be passed down to all children of
// a `Router` component:
export interface RouterChildContext<Params extends { [K in keyof Params]?: string } = {}> {
    router: {
        history: H.History;
        route: {
            location: H.Location;
            match: match<Params>;
        };
    };
}

2
投票

我的解决方法是:

import { useHistory, useLocation } from "react-router-dom";

type THistory<T = unknown> = ReturnType<typeof useHistory<T>>
type TLocation<T = unknown> = ReturnType<typeof useLocation<T>>;

const goTo = (history: THistory<{payload: string}>) => {
  history.push({
    pathname: '/',
    state: { payload: 'some data' },
  });
}

1
投票

您可能想看看 RouterProps 是如何定义的。也许有帮助。

import { useHistory, RouterProps } from 'react-router-dom';

1
投票

你可以这样实现:

const history = useHistory<{ detail: string, response: IHttpResponse }>();

console.log(history.location.state.detail); // should log 'reload'

0
投票

我查看了 useHistory 类型定义并导入了 H。然后我将 useHistory 变量键入为 H.history。

import * as H from 'history';
const history : H.history = useHistory();

© www.soinside.com 2019 - 2024. All rights reserved.