Redux + хуки useDispatch () в useEffect дважды вызывают действие - PullRequest
1 голос
/ 26 мая 2020

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

Я имею в виду эту статью.

Вот пример:

useProfileForm. js

import { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchProfile } from '../../../redux/profile/profile.actions';

const useProfileForm = (callback) => {

    const profileData = useSelector(state =>
        state.profile.items        
    );

    let data;
    if (profileData.profile) {
        data = profileData.profile;
    }

    const [values, setValues] = useState(data);

    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchProfile());
    }, [dispatch]);

    const handleSubmit = (event) => {
        if (event) {
            event.preventDefault();
        }
        callback();
    };

    const handleChange = (event) => {
        event.persist();
        setValues(values => ({ ...values, [event.target.name]: event.target.value }));
    };

    return {
        handleChange,
        handleSubmit,
        values,
    }
};

export default useProfileForm;

Action

export const FETCH_PROFILE_BEGIN = "FETCH_PROFILE_BEGIN";
export const FETCH_PROFILE_SUCCESS = "FETCH_PROFILE_SUCCESS";
export const FETCH_PROFILE_FAILURE = "FETCH_PROFILE_FAILURE";
export const ADD_PROFILE_DETAILS = "ADD_PROFILE_DETAILS";

function handleErrors(response) {
    if (!response.ok) {
        throw Error(response.statusText);
    }
    return response;
}

function getProfile() {
    return fetch("url")
        .then(handleErrors)
        .then(res => res.json());
}

export function fetchProfile() {
    return dispatch => {
        dispatch(fetchProfileBegin());
        return getProfile().then(json => {
            dispatch(fetchProfileSuccess(json));
            return json;
        }).catch(error =>
            dispatch(fetchProfileFailure(error))
        );
    };
}

export const fetchProfileBegin = () => ({
    type: FETCH_PROFILE_BEGIN
});

export const fetchProfileSuccess = profile => {
    return {
        type: FETCH_PROFILE_SUCCESS,
        payload: { profile }
    }
};

export const fetchProfileFailure = error => ({
    type: FETCH_PROFILE_FAILURE,
    payload: { error }
});

export const addProfileDetails = details => {
    return {
        type: ADD_PROFILE_DETAILS,
        payload: details
    }
};

Редуктор:

    import { ADD_PROFILE_DETAILS, FETCH_PROFILE_BEGIN, FETCH_PROFILE_FAILURE, FETCH_PROFILE_SUCCESS } from './profile.actions';

    const INITIAL_STATE = {
        items: [],
        loading: false,
        error: null
    };

    const profileReducer = (state = INITIAL_STATE, action) => {
        switch (action.type) {
            case ADD_PROFILE_DETAILS:
                return {
                    ...state,
                    addProfileDetails: action.payload
                }
            case FETCH_PROFILE_BEGIN:
                return {
                    ...state,
                    loading: true,
                    error: null
                };

            case FETCH_PROFILE_SUCCESS:
                return {
                    ...state,
                    loading: false,
                    items: action.payload.profile
                };

            case FETCH_PROFILE_FAILURE:
                return {
                    ...state,
                    loading: false,
                    error: action.payload.error,
                    items: []
                };
            default:
                return state;
        }
    }

    export default profileReducer;


**Component:**

import React from 'react';
import { connect } from 'react-redux';
import useProfileForm from './useProfileForm';
import { addProfileDetails } from '../../../redux/profile/profile.actions';

const EducationalDetails = () => {

    const { values, handleChange, handleSubmit } = useProfileForm(submitForm);

    console.log("values", values);


    function submitForm() {
        addProfileDetails(values);
    }

    if (values) {
        if (values.error) {
            return <div>Error! {values.error.message}</div>;
        }

        if (values.loading) {
            return <div>Loading...</div>;
        }
    }

    return (
        <Card>
            ...some big html
        </Card>
    )
}

const mapDispatchToProps = dispatch => ({
    addProfileDetails: details => dispatch(details)
});

export default connect(null, mapDispatchToProps)(EducationalDetails);

Также, когда я передаю данные из const [values, setValues] = useState(data); useState в значения, тогда в идеале я должен получить это в компоненте, но я не получаю как это отображается undefined.

const { values, handleChange, handleSubmit } = useProfileForm(submitForm);

значения не определены

enter image description here

enter image description here

1 Ответ

1 голос
/ 26 мая 2020

Двойная отправка действия, вероятно, связана с тем, что вы использовали React.StrictMode в своей иерархии реагирования.

Согласно документации реагирования, чтобы detect unexpected sideEffects, реакция вызывает определенные функции дважды, например

Functions passed to useState, useMemo, or useReducer

Теперь, поскольку response-redux реализован поверх API-интерфейсов React, действия фактически вызываются дважды

Также, когда я передаю данные из const [значения, setValues] = useState (данные); useState для значений, тогда в идеале я должен получить это в компоненте, но я не получаю, так как он показывает undefined.

Чтобы ответить на этот вопрос, вы должны знать, что значения не являются результатом ответа действия отправки из редуктора, но состояние, которое обновляется при вызове handleChange, поэтому предполагается, что действие не влияет на него. *

const useProfileForm = (callback) => {

    const profileData = useSelector(state =>
        state.profile.items        
    );

    let data;
    if (profileData.profile) {
        data = profileData.profile;
    }

    const [values, setValues] = useState(data);

    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchProfile());
    }, [dispatch]);

    const handleSubmit = (event) => {
        if (event) {
            event.preventDefault();
        }
        callback();
    };

    const handleChange = (event) => {
        event.persist();
        setValues(values => ({ ...values, [event.target.name]: event.target.value }));
    };

    return {
        handleChange,
        handleSubmit,
        values,
        data // This is the data coming from redux store on FetchProfile and needs to logged
    }
};

export default useProfileForm;

Вы можете использовать данные в своем компоненте, например,

const { values, handleChange, handleSubmit, data } = useProfileForm(submitForm);
...