Как избежать ненужного повторного рендеринга "stati c компоненты" в функциональном компоненте реакции? - PullRequest
3 голосов
/ 17 января 2020

У меня есть функциональный компонент реагирования, который показывает список тегов и сообщений + несколько сообщений c текст / украшения. Я сохраняю выбранный тег в состоянии, используя useState hook. Сообщения извлекаются с помощью хука apollo useQuery с переменной 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 ]

3 голосов
/ 17 января 2020

Реактивные компоненты перерисовывают каждый раз, когда их состояние или реквизит меняются. Если я правильно читаю, вы меняете тег в состоянии каждый раз, когда изменяется URL-адрес, и таким образом заставляете компонент перерисовываться.

1 голос
/ 18 января 2020

Поскольку ваше состояние объявлено в вашем NewsList компоненте, любое изменение состояния (как другой пользователь указал в своем ответе) вызовет повторную визуализацию всего компонента (NewList) , а не только компоненты, которые вы передали ваше состояние (таким образом, к состоянию c <h1> у вас там).

Если есть части этого компонента, которые не имеют ничего общего с этим состоянием, вы можете переместить их наружу, чтобы избежать повторного рендеринга.

Хотя , в случаях таким образом, рендеринг вашего <h1> не является затратным для React. Вы должны беспокоиться и следовать этому подходу для пользовательских компонентов, где происходят более сложные вещи (например, заполнение списков или вычисление материала и т. П. c ..) В этих случаях вы не хотите, чтобы все эти сложные вещи повторялись, если на них не влияет изменение состояния родителя. Вы также должны всегда учитывать, если перемещение компонента за пределы имеет смысл или, делая это, вы делаете свой код сложным.

Вы всегда должны соблюдать баланс между хорошо организованным и эффективным кодом.

...