简体   繁体   中英

Function being called multiple times in React functional component

Below is the component file 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

Problem/Question : Within the functional component's return, in the third line, I'm making a call to a another function getElt . It seems to be called around 4 or 5 times, which I figured from the console.log I inserted in the first line of the getElt function. I would like to know why it's being called so many times when it should be called just once.

I would like to point out that I do not have any console log statements in the child component Post that is being returned by the function getElt

This is a misconception in React today. Many think that the function component won't be called if the props and state don't change. The truth is, your function may be called many times as the parent component re-renders, and React checks the old Shadow DOM to see if it matches the new Shadow DOM. What we can say, is that the JSX returned won't be updated in the real DOM if props and state haven't been changed.

What you can do to reduce the times the React engine calls you function component, is to try to keep your components from updating unnecessarily (including your parent components). Here are several things I see looking at your code:

  1. A new instance of fetchPost is created each time your function is called. This means on each execution, it will have a different memory address. It's then passed to child components as a props , meaning that every time your SinglePostBySearch component is executed, the children will be forced to render. You might have similar situations in your parent component which are causing this component to be called excessively. To avoid this, any function you pass to children as a prop should be wrapped in a useCallback so that it gets correctly memoized, and doesn't recreate a new instance each time.

  2. You are calling your getElt function every time your component function executes, even if the data hasn't changed. If you needed to prevent the function from executing so many times, it can be useful to either useMemo or useCallback (depending on the use case) and specify the dependencies ( loading , isThereQuery , posts ) in the hook's deps array. This way, the function will only be recalculated when the any of those dependencies are modified.

  3. You are wrapping loading , isThereQuery , and posts in an anonymous object {} each time you pass them around. This is instantiating a new object each time it sees this, which means it has a new memory address -- and will cause any children you pass it to as a prop to re-render. The useState hook already maintains the memory address of the value, so by wrapping it in a new object, you could potentially cause problems.

In React, whenever you use interpolation to bind data directly in the JSX ( {getElt({loading},{isThereQuery},{posts})} ), React considers this a child element. I'm not sure how the anonymous object will affect this, but it doesn't hurt to get rid of the superfluous objects wrapping each parameter, especially since you're destructuring them again in the getElt function anyway.

It's being rendered so many times because the variables you are passing {loading},{isThereQuery},{posts} are changing that many times. If you want to limit how many times it's called you could shortcircuit on one of the values, eg loading && getElt({loading},{isThereQuery},{posts}) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM