【问题标题】:onChange triggering but only performing half of the function?onChange 触发但只执行一半的功能?
【发布时间】:2022-01-06 05:49:46
【问题描述】:

我正在尝试验证电子邮件地址的输入字段。实际的验证工作,状态更新和它周围的一切工作。但是,一旦验证了虚假电子邮件,我注意到一个奇怪的行为。

注意我更改了状态和属性的名称以使其更通用和可读。

<TextField
    label = {emailFieldAttributes.label}
    type = {emailFieldAttributes.type}
    onChange = { event => {
        onChangeHandler(event)
    }}
    id = {emailFieldAttributes.id}
    value = {state.value_email}
    InputProps = {{
        autoComplete: 'off',
        inputMode: 'string'
    }}
    error = {state.error.value}
    ref = {ref}
></TextField>
function onChangeHandler(event)
    {
        if (event.target.id.includes('cc'))
        {
            setState({...state, value_cc: event.target.value});
        }
        else if (event.target.id.includes('body'))
        {
            setState({...state, value_body: event.target.value});
        }
        else
        {
            setState({...state, value_email: event.target.value});
        }
        
        if (state.error != initialErrorState
        )
        {
            resetEmailTooltip();
        }
    }
function resetEmailTooltip()
{
    setEmailStateValues(
    {
        ...state,
        error: resetErrorState
    });
}

在提交按钮的 onClick 中,我运行验证,它会正确更新状态并显示工具提示。事实上,除了 1 个轻微的不良行为外,onChange 可以正常工作。每当验证确实返回 false 并更新 state.error 时,都会显示一个工具提示。下次对输入字段进行更改时,第一个事件仅触发 resetEmailTooltip(); 并且不会更新状态值。

逐步 - 当前行为

  1. 添加格式不正确的电子邮件地址:'test@.test'
  2. 按提交
  3. 验证
  4. 显示工具提示
  5. 首先通过按下例如更改输入字段键盘上的“b”导致 工具提示被移除
  6. 第二次按下“b”将导致“test@b.test”

逐步 - 期望的行为

  1. 添加格式不正确的电子邮件地址:'test@.test'
  2. 按提交
  3. 验证
  4. 显示工具提示
  5. 首先通过按下例如更改输入字段键盘上的“b”导致 工具提示被删除并导致“test@b.test”

我不明白为什么它需要第二个事件来触发状态更新?关于如何触发 onChange,我的思维过程是否有问题?

【问题讨论】:

  • 尝试在控制台上打印您的状态。如果我理解您的问题,它甚至会在第一次发生变化,但以异步方式发生,因此您需要另一个事件才能在页面上正确显示它
  • @Giacomo 嗨,事件本身似乎永远不会更新。 event.target.value 第一个事件永远不会改变。 @Yoshi我看过了,它似乎主要处理状态,而我对字段本身以及事件不更新的原因感到更加困惑。我知道控制台在设置后立即记录状态值将为我提供旧变量,但事件本身应该更新。
  • 没有看到更完整的图片(尤其是&lt;TextField /&gt;),很难判断这里发生了什么。但关于链接的答案:不,这主要不是关于console.logs 可能如何落后。主要的收获是,您不能通过状态更新器功能更新状态并立即使用更新后的状态。对您来说,这意味着,onChangeHandleronChangeHandlerstate.error 不会受到之前的 setState 调用的影响。
  • @Yoshi 我实际上发现了问题并且我即将回答它。当一个接一个地使用 2 个 setStates 时,这是一个糟糕的/新手错误。我只是看不到它,直到我退后一步并尝试了更多的东西。事件问题没有再次发生,只是偶尔发生,所以我也误会了,关于你关于 useState 的评论没有反映变化,这让我朝着正确的方向前进,谢谢!

标签: javascript reactjs react-native onchange


【解决方案1】:

我又挖了一点,发现 event.target.value 确实有点不稳定,但这并不是我问题的真正原因。我的问题源于使用代码中可以看到的 2 个 setStates,我应该早点发现这一点,但刚接触 React 需要一些时间才能弄清楚。

因此,即使事件实际上尝试更新状态,setState 的异步性质似乎被resetEmailTooltip 函数中的第二个 setState 覆盖。我通过将 onChangeHandlerresetEmailTooltip 更改为如下所示解决了这个问题(注意:我不喜欢处理这个问题的代码量,所以我稍后会尝试重写代码) :

function onChangeHandler(event)
{

    if (state.error != initialErrorState )
    {
        resetEmailTooltip(event);
    }
    else
    {
        if (event.target.id.includes('cc'))
        {
            setState({...state, value_cc: event.target.value});
        }
        else if (event.target.id.includes('body'))
        {
            setState({...state, value_body: event.target.value});
        }
        else
        {
            setState({...state, value_email: event.target.value});
        }
    }
}

function resetEmailTooltip(event)
{
    if (event.target.id.includes('cc'))
    {
        setState(
        {
            ...state,
            value_cc: event.target.value,
            error: resetErrorState
        });
    }
    else if (event.target.id.includes('body'))
    {
        setState(
        {
            ...state,
            value_body: event.target.value,
            error: resetErrorState
        });
    }
    else
    {
        setState(
        {
            ...state,
            value_email: event.target.value,
            error: resetErrorState
        });
    }
}

简短的故事是,我在两个函数中都用 event.target.value 更新了状态,并调用了一个 setState 而不是两个。这确保了 event.target.value 已设置,并且我不需要调用这两个 setStates。但是,这仍然感觉很笨拙,我认为有一种方法可以进一步缩短此代码并摆脱几个 if 语句,我会研究一下。


更新: 由于使用相同的值更新本地状态不会导致重新渲染,因此我决定删减更多代码,甚至删除 resetEmailTooltip(event) 函数。我将onChangeHandler(event) 更改为以下代码,它的工作方式与我想要的完全一样,我什至还需要对其进行一些清理。如果可能的话,我会考虑在 setState 中设置内部条件,但我不确定这是否允许。这是目前的最终结果,如果他们像我遇到同样的问题一样遇到困难,希望它可以帮助任何人。

function onChangeHandler(event)
{
    const resetErrorState = state.initialErrorState;

    if (event.target.id.includes('cc'))
    {
        setState(
            {
                ...state,
                value_cc: event.target.value,
                error: resetErrorState
            }
        );
    }
    else if (event.target.id.includes('body'))
    {
        setState(
            {
                ...state,
                value_body: event.target.value,
                error: resetErrorState
            }
        );
    }
    else
    {
        setState(
            {
                ...state,
                value_email: event.target.value,
                error: resetErrorState
            }
        );
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-09
    • 2012-08-25
    • 2021-08-16
    • 2021-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多