Почему мой компонент react отключен после ошибки выборки

#reactjs #typescript #react-hooks

Вопрос:

Я все. Я пытаюсь опубликовать простую форму входа в систему с пользовательским крючком для выборки. Вход в систему работает нормально, если я хорошо аутентифицируюсь в первый раз. Но в случае ошибки, если я попытаюсь повторно проверить форму, компонент, похоже, размонтирован (вызывается функция очистки крючков), и я не могу повторно настроить свой api. Почему этот компонент размонтирован, я не понимаю ? Спасибо за вашу помощь

signin.ts (код был упрощен)

 import React, { useState } from 'react'
import useFetch from '../shared/hooks/useFetch'


const Signin: React.FunctionComponent = () => {

    const [postData, setPostData] = useState({
        url: "",
        options: {}
    })

    type ResponseT = {
        id: string,
        firstname: string,
        lastname: string,
        roles: string[],
        accessToken: string
    } amp; string

   const { data, error } = useFetch<ResponseT>(postData.url, postData.options)
   const handleSubmit = (e: any) => {
        if (e) e.preventDefault()
        setPostData({
            url: `${process.env.REACT_APP_API_HOST}/signin`,
            options: {
                method: "POST",
                body: JSON.stringify({
                    email: "testt@test.fr",
                    password: "bla"
                })
            }
        })
    }
    return (
        <form>
            <div>
                <div className="form-group">
                    <button onClick={handleSubmit} className="btn btn-primary btn-block">Sign In</button>
                    {error amp;amp; <p>{error}</p>}
                    {data === '' amp;amp; <p style={{ height: '100px', backgroundColor: 'red' }}>Loading...</p>}
                </div>

            </div>
        </form>
    )
}

export default Signin

 

Полезная информация.ts

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

interface State<T> {
    data?: T
    error?: Error
}

type Cache<T> = { [url: string]: T }

type Action<T> =
    | { type: 'loading' }
    | { type: 'fetched'; payload: T }
    | { type: 'error'; payload: Error }

function useNiceFetch<T = unknown>(url?: string, options?: RequestInit): State<T> {
    const cache = useRef<Cache<T>>({})

    const cancelRequest = useRef<boolean>(false)

    const initialState: State<T> = {
        error: undefined,
        data: undefined,
    }

    const fetchReducer = (state: State<T>, action: Action<T>): State<T | any> => {
        switch (action.type) {
            case 'loading':
                return { ...initialState, data: '' }
            case 'fetched':
                return { ...initialState, data: action.payload }
            case 'error':
                return { ...initialState, error: action.payload }
            default:
                return state
        }
    }

    const [state, dispatch] = useReducer(fetchReducer, initialState)

    useEffect(() => {
        if (!url) return

        const fetchData = async () => {
            if (cancelRequest.current) return
            dispatch({ type: 'loading' })

            if (cache.current[url]) {
                dispatch({ type: 'fetched', payload: cache.current[url] })
                return
            }

            try {
                const response = await fetch(url, options) as any
                const responseJson = await response.json()
                if (!response.ok) {
                    throw responseJson
                }

                cache.current[url] = responseJson as T

                dispatch({ type: 'fetched', payload: responseJson })
            } catch (error) {
                if (cancelRequest.current) return

                dispatch({ type: 'error', payload: error as Error })
            }
        }

        fetchData()

        return () => {
            cancelRequest.current = true
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [url, options])

    return state
}

export default useFetch
 

Комментарии:

1. Я не думаю, что это из-за того, что компонент отключается, а скорее из-за того, что запускается повторная передача, и это устанавливает значение cancelRequest ref true, и у вас нет никакого способа сбросить его. Я думаю, вам следует пересмотреть структуру кода, поскольку в настоящее время у вас нет возможности повторно запросить что-либо без повторного подключения компонента. useFetch Крючок должен возвращать функцию выборки для вызова, а также значение ответа. Пользовательская функция выборки должна использовать для запроса маркер отмены, а не ссылку React для любого вида отслеживания жизненного цикла.

2. Спасибо вам за ваш ответ. я постараюсь это сделать.