【问题标题】:How can i get setState to work in an event handler in a functional React component如何让 setState 在功能性 React 组件的事件处理程序中工作
【发布时间】:2020-09-28 22:44:56
【问题描述】:

我正在重构一个 MERN 应用程序以使用钩子和上下文,因此我将类组件更改为函数。一个组件有一个表单,它根据输入字段中的击键改变状态,例如:

    class CreateAccountComp extends Component {
      constructor(props) {
      super(props);

      this.state = {
        firstName: null,
        lastName: null,
        email: null,
        password: null,
        githubID: null,
    };
  }

  handleSubmit = (e) => {
    e.preventDefault();
    this.props.handleInputChange();
    API.getsync(this.state.githubID, this.state.firstName, this.state.lastName, this.state.email);
    ...
    })
  };

  handleChange = (e) => {
    e.preventDefault();
    const { name, value } = e.target;
    ...
    this.setState({ [name]: value }, () => null);
  };
  ....

在将回调添加到 'this.setState' 语句后,此方法有效。

新组件如下所示:

const CreateAccountComp = (props) => {

  const [state, setState] = useState({
    firstName: null,
    lastName: null,
    email: null,
    password: null,
    githubID: null,
  });

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log("HMMMM leaving CreateAccountcomp");
    props.handleInputChange();
    API.getsync(state.githubID, state.firstName, state.lastName, state.email);
    ...
  };

  const handleChange = (e) => {
    e.preventDefault();
    const { name, value } = e.target;
    ...
    setState({ [name]: value });
  };

现在,我不能使用回调来处理异步setState 语句,并且传递给API.getsync() 函数的状态属性是未定义的。

我的研究提出了使用 async/await 或 useEffect 的示例,但它们都处理对外部 api 的单个调用。在这里,我运行handleChange 以将击键呈现到表单中的输入字段中,然后通过onSubmit 运行handleSubmit 以执行基于状态值更新数据库的函数。有没有办法在这个函数组件中正确更新状态?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    您可以使用useEffect 钩子并将state 添加为useEffect 钩子的依赖项,以便在每次state 对象更改时运行

    useEffect(() => {
        // code to run every time `state` object changes
        API.getsync(state.githubID, state.firstName, state.lastName, state.email);
    }, [state]);
    

    您也没有正确更新状态。与 this.setState 将前一个状态与新状态合并的不同,useState 钩子返回的函数将用新状态覆盖前一个状态。

    为避免覆盖状态,请确保手动将之前的状态与新的状态合并

    const handleChange = (e) => {
        e.preventDefault();
        const { name, value } = e.target;
    
        setState({ ...state, [name]: value });
    };
    

    请记住,useEffect 钩子也会在组件第一次渲染时运行。之后,它只会在state 对象发生变化时运行。

    编辑:

    如果您不想在 useEffect 在组件的初始渲染时运行时发出 HTTP 请求,请在 useEffect 钩子的回调中添加一个 if 语句,以确保 HTTP 请求仅在您在 state 对象中有必要的数据来发出 HTTP 请求

    useEffect(() => {
    
        if (state.githubID) {
            API.getsync(state.githubID, state.firstName, state.lastName, state.email);
        }
    
    }, [state]);
    

    【讨论】:

    • 我试过这个,问题是'getsync'在加载时运行,它将坏数据加载到我的数据库中并跳过提供github用户名的表单。显然,当 github api 遇到未定义的用户名时,它会返回一些随机信息。我通过从 useEffect 中删除代码解决了这个问题。粗鲁,但它有效。
    • 您可以通过添加一个 if 语句来检查您在状态中是否有所需的数据来发出请求,从而防止 useEffect 在组件第一次呈现时发出 HTTP 请求。查看更新的答案。
    【解决方案2】:

    Yousaf 让我走上了正轨,但是需要修改代码才能正常工作。这个问题是通过执行 'API.getsync(state.githubID, state.firstName, state.lastName, state.email);'在初始加载时,数据库正在接收数据,该数据告诉应用程序来自 github 的用户信息在那里,并且从未呈现输入用户名的表单。显然,如果用户名未定义,github api 将响应有效但不正确的信息。该api通过以下方式命中:

    axios
    .get(
      "https://api.github.com/users/" + developerLoginName + "/repos?type=all"
    

    这导致将用户“null”的 4 个存储库的信息添加到数据库中!

    已通过从 useEffect 中删除调用 getsync 函数的行来解决此问题。

    但是,我发现根本不需要 useEffect。只需将扩展运算符添加到“setState”即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-22
      • 2021-04-20
      • 1970-01-01
      • 2021-09-11
      • 1970-01-01
      • 2019-12-11
      相关资源
      最近更新 更多