为什么在更新钩子值之前会发生 redux 调度?

IT技术 javascript reactjs redux
2021-05-28 00:43:09

我的代码中有一个有趣的问题,我不确定它为什么会发生。希望有人能解释一下。基本上,在调用“调度”方法之前,我使用“setValues”作为我的钩子。但是,似乎在更新钩子中的值之前仍然触发了调度。尽管在我看来它应该是相反的。为什么会发生这种情况?这是一些代码:

import React, { useState } from 'react';
import Grid from '@material-ui/core/Grid';
import InputField from 'shared/components/form/Inputfield';
import DatePicker from 'shared/components/pickers/DatePicker';
import InfoButton from 'shared/components/buttons/InfoButton';
import CustomButton from 'shared/components/buttons/CustomButton';
import TextArea from 'shared/components/form/TextArea';
import { connect } from 'react-redux';

export function ProjectDetails(props) {
    const [values, setValues] = React.useState({
        full_project_name: ' ',
        short_name: ' ',
        associated_projects: ' ',
        short_description: ' ',
    });

    const handleInputFieldChange = field_name => event => {
        setValues({ ...values, [field_name]: event.target.value });
        //why does dispatch happen before values are updated?
        props.dispatch({ type: 'PLEASE_WORK', payload: values });


    };

    console.log('Project values', values);

    return (
        <>
            <h1>Project Details</h1>
            <Grid container spacing={1}>
                <Grid item xs={12}>
                    <h3>Full project name *</h3>
                </Grid>
                <Grid item xs={12}>
                    <InputField
                        handler={handleInputFieldChange('full_project_name')}
                        placeHolderText="Please type the last letter two times"
                    />
                </Grid>
                <Grid item xs={12}>
                    <h3>Short name (Acronym)</h3>
                </Grid>
                <Grid item xs={12}>
                    <InputField handler={handleInputFieldChange('short_name')} />
                </Grid>
            </Grid>
        </>
    );
}

function mapStateToProps(state) {
    return {
        full_project_name: state.projectReducer.full_project_name,
        short_name: state.projectReducer.short_name,
    };
}

export default connect(mapStateToProps)(ProjectDetails);

3个回答

React setState 是异步的,这意味着当您调用setValues设置values的状态时,它会启动该过程,但在必须完成之前继续执行下一行。

您也可以使用确切的值调用 dispatch 以确保它是正确的,例如 props.dispatch({ type: 'PLEASE_WORK', payload: { ...values, [field_name]: event.target.value } });

为了进一步补充 Maddo 的答案,如果你仔细想想,最终,React 组件实际上只是一个在某个时候被调用的常规函数​​:

export function ProjectDetails(props)

因此,当函数被调用时,其作用域内的变量只保存函数被调用时存在的值(比方说,在渲染运行时):

const [ values, setValues ] = useState(...); // <-- values is const

本质上,values不会在当前“运行”中改变,并且只有在下一次渲染组件之后才会改变。请注意,它甚至声明为const确保我们无法触摸它;)

这里 console.log(values) 的结果是什么?

如果有疑问,console.log 可以成为您的朋友(使用警报更有趣!)

const handleInputFieldChange = field_name => event => {
  setValues({ ...values, [field_name]: event.target.value });

  // -> what is the result of values here ? (hint: values is const)
  console.log('values is:', JSON.stringify(values));

  props.dispatch({ type: 'PLEASE_WORK', payload: values });
};

我更喜欢这样做的方式是简单地将所有内容放在一个新变量中,以确保我们正在使用:

const handleInputFieldChange = field_name => event => {
  const newValues = { ...values, [field_name]: event.target.value };

  setValues(newValues);
  props.dispatch({ type: 'PLEASE_WORK', payload: newValues });
};

这使得浏览代码更容易理解:您创建了一个 newValues,将它设置在状态中,然后用它调度一个动作。

希望这是有道理的!

UseEffect还可以帮助您解决异步调用“setValues”的问题。

您可以将“值”设置为依赖项useEffect,然后只需在 useEffect 中触发调度即可。

我在这里创建了一个演示:

编辑 useState 是异步函数

请查看控制台日志。