【问题标题】:Function being called multiple times in React functional component在 React 功能组件中多次调用函数
【发布时间】:2020-04-23 18:20:46
【问题描述】:

下面是组件文件SinglePostBySearch.js

import React, { useState } from 'react'
import Post from './Post'
const axios = require('axios')

const getElt=({loading},{isThereQuery},{posts})=>{
    console.log(posts)
    if(!loading && isThereQuery)
    {
        return(
            <Post post={posts} id={posts.id} /> 
        )
    }
    if(loading)
    {
        return <div>Loading</div>
    }
    if(!(loading && posts))
    {
        return <div>No post from the user</div>
    }
}

function SinglePostBySearch(props) {
    const [posts, setPosts] = useState({})
    const [isThereQuery,setIsThereQuery]=useState(false)
    const [loading,setIsLoading]=useState(false)
    const fetchPost = (event) => {
        const postId = event.target.value
        if (postId) {
            setIsThereQuery(false)
            setIsLoading(true)
            axios.get(`https://jsonplaceholder.typicode.com/posts/${postId}`).then(res => {
                setPosts(res.data)
                setIsThereQuery(true)
                setIsLoading(false)
            }).catch(err => {
                console.log(err)
                setIsLoading(false)
                setPosts({})
            })
        }
        else{
            setPosts({})
            setIsThereQuery(false)
        }

    }
    return (
        <div>
            Hello {props.username}, enter a <strong>userId</strong> below
            <input type="text" onChange={fetchPost} />
            {getElt({loading},{isThereQuery},{posts})}
        </div>
    )
}
export default SinglePostBySearch

问题/问题:在功能组件的返回中,在第三行中,我正在调用另一个函数 getElt。它似乎被调用了大约 4 或 5 次,这是我从 getElt 函数的第一行中插入的 console.log 计算出来的。我想知道为什么它被调用了这么多次,而它应该只调用一次。

我想指出的是,函数 getElt

返回的子组件 Post 中没有任何控制台日志语句

【问题讨论】:

  • getElt 将在 SinglePostBySearch 被重新渲染时被调用 - 每当它的道具发生变化时。这种情况经常发生并不少见,但我们无法确定,因为您没有显示任何渲染它的父组件。

标签: javascript reactjs react-hooks


【解决方案1】:

这是当今 React 中的一个误解。许多人认为如果 props 和 state 没有改变,函数组件就不会被调用。事实上,当父组件重新渲染时,你的函数可能会被多次调用,React 会检查旧的 Shadow DOM 以查看它是否与新的 Shadow DOM 匹配。我们可以说的是,如果 props 和 state 没有改变,返回的 JSX 不会在真实的 DOM 中更新。

为了减少 React 引擎调用函数组件的次数,你可以做的是尽量避免你的组件进行不必要的更新(包括你的父组件)。以下是我在查看您的代码时看到的几件事:

  1. 每次调用您的函数时都会创建一个 fetchPost 的新实例。这意味着在每次执行时,它将具有不同的内存地址。然后它作为props 传递给子组件,这意味着每次执行SinglePostBySearch 组件时,子组件将被强制渲染。您的父组件中可能有类似的情况导致该组件被过度调用。为避免这种情况,您作为prop 传递给children 的任何函数都应包装在useCallback 中,以便正确记忆,并且不会每次都重新创建新实例。

  2. 每次执行组件函数时都会调用getElt 函数,即使数据没有更改。如果您需要阻止函数执行这么多次,useMemouseCallback(取决于用例)并指定依赖关系(loadingisThereQueryposts)可能很有用在钩子的deps 数组中。这样,只有在修改了这些依赖项中的任何一个时,才会重新计算函数。

  3. 每次传递loadingisThereQueryposts 时,它们都会被包装在一个匿名对象{} 中。每次看到它时都会实例化一个新对象,这意味着它有一个新的内存地址——并且会导致你将它作为道具传递给任何子对象重新渲染。 useState 钩子已经维护了值的内存地址,因此通过将其包装在一个新对象中,可能会导致问题。

在 React 中,每当您使用插值直接在 JSX ({getElt({loading},{isThereQuery},{posts})}) 中绑定数据时,React 都会将此视为子元素。我不确定匿名对象将如何影响这一点,但摆脱包装每个参数的多余对象并没有什么坏处,尤其是因为无论如何您都在 getElt 函数中再次解构它们。

【讨论】:

    【解决方案2】:

    它被渲染了很多次,因为您传递的变量{loading},{isThereQuery},{posts} 正在改变很多次。如果你想限制它被调用的次数,你可以短路其中一个值,例如loading &amp;&amp; getElt({loading},{isThereQuery},{posts}).

    【讨论】:

      猜你喜欢
      • 2021-08-16
      • 2021-07-15
      • 1970-01-01
      • 2021-04-22
      • 2021-11-22
      • 2020-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多