我有一个react功能组件,它显示标签和帖子列表以及一些静态文本/装饰。我使用useState
钩子将当前选定的标签存储在一个状态中。通过使用带有useQuery
变量的apollo的tag
挂钩来获取帖子。用户应该能够选择一个标签,它将替换当前的tag
状态-因此useQuery(POSTS_QUERY)
将使用新的tag
变量重新运行。
const onTagSelectChange = (window: Window,
router: NextRouter,
name: string,
checked: boolean,
tagSetter: React.Dispatch<React.SetStateAction<string>>) => {
if (checked) {
setTagQueryInUrl(window, router, name)
tagSetter(name)
} else {
setTagQueryInUrl(window, router, null)
tagSetter(null)
}
}
const NewsList: NextPage = () => {
const router = useRouter()
const query = router.query as Query
// store tag in state
// initialize tag from `tag` query
const [tag, setTag] = useState(query.tag)
const { data: postsData, loading: postsLoading, error: postsError } = useQuery(
POSTS_QUERY,
{
variables: {
tag: tag
}
}
)
const { data: tagsData, loading: tagsLoading, error: tagsError } = useQuery(TAGS_QUERY)
// show error page if either posts or tags query returned error
if (postsError || tagsError) {
return <Error statusCode={500} />
}
return (
<div>
<h1>Here we have list of news, and I should not re-render everytim :(</h1>
<Tags
loading={tagsLoading}
data={tagsData}
isChecked={(name) => name === tag}
onChange={(name, checked) => onTagSelectChange(window, router, name, checked, setTag)}
/>
<Posts loading={postsLoading} data={postsData} />
</div>
)
}
我的问题是,即使我没有传递任何内容,为什么我的h1
块仍继续重新渲染?还是我完全误解了反应的原理?
答案 0 :(得分:3)
只要组件的状态或道具发生变化,反应组件就会重新渲染。如果我没看错的话,那么每当url更改时,您都在更改标记的状态,从而使组件重新呈现。
答案 1 :(得分:1)
当您在NewsList
组件上声明您的状态时,任何状态更改(如另一位用户在其答案中所述)将触发重新呈现整个组件(NewList),并且不仅要传递到您已经通过状态的组件(因此要传递到那里的静态<h1>
)。
如果该组件的某些部分与该状态无关,则可以将其移到外部以避免重新渲染。
尽管,在这种情况下,重新渲染<h1>
并不是React的代价。您应该担心并在处理复杂情况的自定义组件上遵循此方法(例如,填充列表或计算内容等)。在这些情况下,如果它们不受父级状态更改的影响,则您不希望所有这些复杂的事情再次发生。您还应该始终考虑一下,如果将组件移出外部是有意义的,或者这样做,会使代码变得复杂。
您应该始终在组织良好和高效的代码之间取得平衡。