下面是组件文件 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
返回的控制台日志语句。答案 0 :(得分:1)
今天在React中这是一个误解。许多人认为,如果道具和状态不变,则不会调用功能组件。事实是,当父组件重新渲染时,您的函数可能会多次调用,React会检查旧的Shadow DOM以查看其是否与新的Shadow DOM相匹配。我们可以说的是,如果props和state不变,返回的JSX不会在真实DOM中更新。
您可以采取的措施来减少React引擎调用您的功能组件的时间,以防止不必要地更新您的组件(包括您的父组件)。我在查看您的代码时会看到以下几件事:
每次调用函数时,都会创建一个fetchPost
的新实例。这意味着在每次执行时,它将具有不同的内存地址。然后将其作为props
传递到子组件,这意味着每次执行SinglePostBySearch
组件时,将强制子组件进行渲染。您的父组件中可能有类似的情况,导致该组件被过度调用。为避免这种情况,应将以children
形式传递给prop
的任何函数都包装在useCallback
中,以便正确地记住它,并且不会每次都重新创建新实例。 / p>
即使组件数据未更改,每次执行组件函数时,您都在调用getElt
函数。如果您需要阻止函数执行多次,可以使用useMemo
或useCallback
(取决于用例)并指定依赖项(loading
,{{ 1}},isThereQuery
)在挂钩的posts
数组中。这样,只有在修改了这些依赖项中的任何一个时,函数才会重新计算。
您每次将deps
,loading
和isThereQuery
包装在匿名对象posts
中时,都会将它们包装在一起。每次看到此对象都会实例化一个新对象,这意味着它具有一个新的内存地址-并将导致将其传递给的所有子对象作为重新渲染的道具。 {}
钩子已经维护了该值的内存地址,因此通过将其包装在新对象中,可能会引起问题。
在React中,每当您使用插值直接在JSX(useState
)中绑定数据时,React都将其视为子元素。我不确定匿名对象将如何影响这一点,但是摆脱多余的对象包装每个参数并没有什么害处,特别是因为无论如何您还是要在{getElt({loading},{isThereQuery},{posts})}
函数中对其进行销毁。>
答案 1 :(得分:0)
它被渲染了很多次,因为您传递的变量{loading},{isThereQuery},{posts}
改变了很多次。如果您想限制它被调用的次数,则可以短路其中一个值,例如loading && getElt({loading},{isThereQuery},{posts})
。