如何避免在反应功能组件中不必要地重新渲染“静态组件”?

时间:2020-01-17 16:13:32

标签: javascript reactjs typescript react-hooks next.js

我有一个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块仍继续重新渲染?还是我完全误解了反应的原理?

Here I click on tags, and it shows h1 element keeps re-rendering

2 个答案:

答案 0 :(得分:3)

只要组件的状态或道具发生变化,反应组件就会重新渲染。如果我没看错的话,那么每当url更改时,您都在更改标记的状态,从而使组件重新呈现。

答案 1 :(得分:1)

当您在NewsList组件上声明您的状态时,任何状态更改(如另一位用户在其答案中所述)将触发重新呈现整个组件(NewList),并且不仅要传递到您已经通过状态的组件(因此要传递到那里的静态<h1>)。

如果该组件的某些部分与该状态无关,则可以将其移到外部以避免重新渲染。

尽管,在这种情况下,重新渲染<h1>并不是React的代价。您应该担心并在处理复杂情况的自定义组件上遵循此方法(例如,填充列表或计算内容等)。在这些情况下,如果它们不受父级状态更改的影响,则您不希望所有这些复杂的事情再次发生。您还应该始终考虑一下,如果将组件移出外部是有意义的,或者这样做,会使代码变得复杂。

您应该始终在组织良好和高效的代码之间取得平衡。