Преобразование компонента класса React в компонент React Hook

Я хочу преобразовать этот компонент класса реакции в компонент хуков реакции. Я преобразовал большую часть кода, и теперь мне нужна помощь в преобразовании той части кода, которая находится между функциями рендеринга и возврата.

Вот компонент класса:

class LoginGoogle extends React.Component {
    state = {
        loading: true,
        error: null,
        data: {},
    };

    componentDidMount() {
        fetch(`/api/auth/google/callback${this.props.location.search}`, { headers: new Headers({ accept: 'application/json' }) })
            .then((response) => {
                if (response.ok) {
                    return response.json();
                }
                throw new Error('Something went wrong!');
            })
            .then((data) => {
                this.setState({ loading: false, data });
            })
            .catch((error) => {
                this.setState({ loading: false, error });
                console.error(error);
            });
    }

    render() {
        const { loading, error, data } = this.state;
        if (loading) {
            return <Layout>Loading....</Layout>;
        }

        if (error) {
            return (
                <Layout>
                    <div>
                        <p>Error:</p>
                        <code className="Code-block">{error.toString()}</code>
                    </div>
                </Layout>
            );
        }

        return (
            <Layout>
                <div>
                    <details>
                        <summary>Welcome {data.user.name}</summary>
                        <p>Here is your info: </p>
                        <code className="Code-block">{JSON.stringify(data, null, 2)}</code>
                    </details>
                </div>
            </Layout>
        );
    }
}

И это новый компонент перехватчиков реакции, который я создал. Как я уже упоминал ранее, он еще не закончен.

function LoginGoogle (props) {

    const [start, setStart] = useState(
        {
        loading: true,
        error: null,
        data: {},
           }
    )

    useEffect(() => {
        fetch(`/api/auth/google/callback${props.location.search}`, { headers: new Headers({ accept: 'application/json' }) })
            .then((response) => {
                if (response.ok) {
                    return response.json();
                }
                throw new Error('Something went wrong!');
            })
            .then((data) => {
                setStart({ loading: false, data });
            })
            .catch((error) => {
                setStart({ loading: false, error });
                console.error(error);
            });
    })


        const { loading, error, data } = this.state;
        if (loading) {
            return <Layout>Loading....</Layout>;
        }

        if (error) {
            return (
                <Layout>
                    <div>
                        <p>Error:</p>
                        <code className="Code-block">{error.toString()}</code>
                    </div>
                </Layout>
            );
        }

        return (
            <Layout>
                <div>
                    <details>
                        <summary>Welcome {data.user.name}</summary>
                        <p>Here is your info: </p>
                        <code className="Code-block">{JSON.stringify(data, null, 2)}</code>
                    </details>
                </div>
            </Layout>
        );
    }

Вот шаги, которые я предпринял для преобразования кода: 10 шагов для преобразования компонента класса React в функциональный компонент React с помощью хуков!


person Ala Ben Aicha    schedule 29.05.2020    source источник


Ответы (2)


Прежде всего, логика из componentDidMount должна быть внутри хука useEffect, что вы поняли. Однако вам нужно будет добавить пустой массив в качестве массива зависимостей, который гарантирует, что HTTP-запрос будет вызываться один раз при монтировании:

useEffect(() => {
    fetch(`/api/auth/google/callback${props.location.search}`, { headers: new Headers({ accept: 'application/json' }) })
        .then((response) => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Something went wrong!');
        })
        .then((data) => {
            setStart({ loading: false, data });
        })
        .catch((error) => {
            setStart({ loading: false, error });
            console.error(error);
        });
}, []);

При этом вы должны условно отображать элементы JSX на основе состояния вашего компонента, как определено состоянием start:

const { data, error, loading } = start;

return (
  <>
    {error && (
       <Layout>
         <div>
           <p>Error:</p>
           <code className="Code-block">{error.toString()}</code>
           </div>
       </Layout>
    )}
    {data && (
      <Layout>
        <div>
           <details>
             <summary>Welcome {data.user.name}</summary>
             <p>Here is your info: </p>
             <code className="Code-block">{JSON.stringify(data, null, 2)}</code>     </details>
         </div>
      </Layout>
    )}
    {
      loading && <Layout>Loading....</Layout>
    }
  <>
);
person wentjun    schedule 29.05.2020

Прямо сейчас ваш запрос на выборку выполняется для КАЖДОЙ визуализации, если вы хотите имитировать поведение componentDidMount, вам нужно будет передать пустой массив зависимостей в useEffect

useEffect(() => {
    fetch(`/api/auth/google/callback${props.location.search}`, { headers: new Headers({ accept: 'application/json' }) })
        .then((response) => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Something went wrong!');
        })
        .then((data) => {
            setStart({ loading: false, data });
        })
        .catch((error) => {
            setStart({ loading: false, error });
            console.error(error);
        });
}, []) // See the empty dependency array

Добавив пустой список зависимостей, он запустится один раз.

const { loading, error, data } = this.state

становится

const {loading, error, data} = start

person Paul McLoughlin    schedule 29.05.2020
comment
А как насчет строк кода после метода рендеринга? Как я могу это изменить? - person Ala Ben Aicha; 29.05.2020