繁体   English   中英

Redux + 钩子 useDispatch() 在 useEffect 调用动作两次

[英]Redux + Hooks useDispatch() in useEffect calling action twice

我是 redux 和挂钩的初学者。 我正在处理表单并尝试通过useDispatch挂钩调用操作,但它调用了我的操作两次。

我指的是这篇文章。

这是示例:

使用ProfileForm.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;

行动

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 到值,那么理想情况下我应该在组件中收到它,但我没有得到它,因为它显示未定义。

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

值未定义

在此处输入图像描述

在此处输入图像描述

两次分派动作可能是因为您在反应层次结构中使用React.StrictMode

根据反应文档,为了detect unexpected sideEffects ,反应两次调用某些函数,例如

Functions passed to useState, useMemo, or useReducer

现在由于 react-redux 是在 react API 之上实现的,因此实际上会调用两次操作

此外,当我从 const [values, setValues] = useState(data); 传递数据时 useState 到值,那么理想情况下我应该在组件中收到它,但我没有得到它,因为它显示未定义。

要回答这个问题,您必须知道 values 不是来自 reducer 的调度操作响应的结果,而是一个 state 在调用 handleChange 时更新,因此应该不受操作的影响

我认为您的意思是从忘记做的useProfileForm公开 redux 数据

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM