在React功能组件中多次调用该函数

时间:2020-04-23 18:20:46

标签: javascript reactjs react-hooks

下面是组件文件 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 。从我在 getElt 函数的第一行中插入的console.log中可以看出,它大约被调用了4到5次。我想知道为什么只调用一次它就会被调用那么多次。

我想指出的是,子组件 Post 中没有任何由功能 getElt

返回的控制台日志语句。

2 个答案:

答案 0 :(得分:1)

今天在React中这是一个误解。许多人认为,如果道具和状态不变,则不会调用功能组件。事实是,当父组件重新渲染时,您的函数可能会多次调用,React会检查旧的Shadow DOM以查看其是否与新的Shadow DOM相匹配。我们可以说的是,如果props和state不变,返回的JSX不会在真实DOM中更新。

您可以采取的措施来减少React引擎调用您的功能组件的时间,以防止不必要地更新您的组件(包括您的父组件)。我在查看您的代码时会看到以下几件事:

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

  2. 即使组件数据未更改,每次执行组件函数时,您都在调用getElt函数。如果您需要阻止函数执行多次,可以使用useMemouseCallback(取决于用例)并指定依赖项(loading,{{ 1}},isThereQuery)在挂钩的posts数组中。这样,只有在修改了这些依赖项中的任何一个时,函数才会重新计算。

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

在React中,每当您使用插值直接在JSX(useState)中绑定数据时,React都将其视为子元素。我不确定匿名对象将如何影响这一点,但是摆脱多余的对象包装每个参数并没有什么害处,特别是因为无论如何您还是要在{getElt({loading},{isThereQuery},{posts})}函数中对其进行销毁。

答案 1 :(得分:0)

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