【问题标题】:React Too many re-renders反应太多重新渲染
【发布时间】:2020-04-12 01:21:49
【问题描述】:

我正在关注 serverless-stack.com 教程。但是我在创建登录按钮后被卡住了。

我不断收到错误:

Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

我不知道是什么导致了这么多次渲染。 我组合了我的 LoaderButton 而不是导入以使其更简单。

import React, { useState } from "react";
import { Auth } from "aws-amplify";
import { useHistory } from "react-router-dom";
import { FormGroup, FormControl, ControlLabel } from "react-bootstrap";
import { useFormFields } from "../libs/hooksLib";
import { onError } from "../libs/errorLib";
import "../css/index.css";

const LoaderButton = (
  isLoading,
  className = "",
  disabled = false,
  ...props ) => {
    return(
    <Button
      className={`LoaderButton ${className}`}
      disabled={disabled || isLoading}
      {...props}
    >
      {isLoading && <Glyphicon glyph="refresh" className="spinning" />}
      {props.children}
    </Button>
    )
};

export default function Login() {
  let history = useHistory();
  const [isLoading, setIsLoading] = useState(false);
  const [fields, handleFieldChange] = useFormFields({
    email: "",
    password: ""
  });

  function validateForm() {
    return fields.email.length > 0 && fields.password.length > 0;
  }

  async function handleSubmit(event) {
    event.preventDefault();

    setIsLoading(true);

    try {
      await Auth.signIn(fields.email, fields.password);
      userHasAuthenticated(true);
      console.log(history);
      //history.push("/");
    } catch (e) {
      onError(e);
      setIsLoading(false);
    }
  }

  return (
    <div className="Login">
      <form onSubmit={ () => { handleSubmit() } }>
        <FormGroup controlId="email" bsSize="large">
          <ControlLabel>Email</ControlLabel>
          <FormControl
            autoFocus
            type="email"
            value={fields.email}
            onChange={ () => { handleFieldChange() } }
          />
        </FormGroup>
        <FormGroup controlId="password" bsSize="large">
          <ControlLabel>Password</ControlLabel>
          <FormControl
            type="password"
            value={fields.password}
            onChange={ () => { handleFieldChange() } }
          />
        </FormGroup>
          <LoaderButton
            block
            type="submit"
            bsSize="large"
            isLoading={ () => { isLoading() } }
            disabled={() => { !validateForm() }}
          >
            Login
          </LoaderButton>
      </form>
    </div>
  );
}

hooksLib.js / useFormFields

import { useState } from 'react'

const useFormFields = (initalState) => {
  const [fields, setValues] = useState(initalState)

  return [
    fields,
    setValues({
      ...fields,
      [event.target.id]: event.target.value
    })
  ]
}

export { useFormFields }

【问题讨论】:

  • 您的示例中缺少一些代码:userHasAuthenticatedhandleFieldChange。另外,你能包括useFormFields吗?
  • 您可以尝试的一件事是删除代码,直到您的渲染问题消失。它可能会帮助您缩小导致问题的范围。
  • 我觉得很奇怪您将函数作为 disabled 属性传递。那不应该是一个布尔值吗,比如:disabled={!validateForm()}
  • @tintef 是的,我进行了这些更改,因为有时当您尝试传递函数调用时会弹出此错误,因此我使用箭头函数遵循该模式。我改回来了。
  • @Cully 行动!我留下了那个代码,因为我实际上是在做你所说的。我会添加回来并添加更多代码。

标签: javascript reactjs react-hooks


【解决方案1】:

如果您想接受 event 值,您的自定义挂钩应如下所示:

const useFormFields = (initalState) => {
  const [fields, setValues] = useState(initalState)

  return [
    fields,
    (event) => setValues({
      ...fields,
      [event.target.id]: event.target.value
    })
  ]
}

因为该参数实际上是一个应该发生的回调。


另外,您的 LoadingButton 实现需要更改为:

<LoaderButton
  block
  type="submit"
  bsSize="large"
  isLoading={isLoading} // This is a boolean value, not a function
  disabled={() => !validateForm()}
>...</LoaderButton>

【讨论】:

  • 太棒了!我错过了一个事实,它是一个接收事件的函数,这更有意义!哈哈,我确实有过这样的情况,但 cmets 中有人说应该是另一种方式。谢谢,我会做出改变,让你知道结果如何。
  • 不客气 :) 很高兴它有帮助,乍一看很难发现,所以我不怪你 ;)
猜你喜欢
  • 1970-01-01
  • 2021-02-23
  • 2020-09-29
  • 2020-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-23
  • 2020-11-27
相关资源
最近更新 更多