javascript - Jak se vyhnout zbytečnému přerenderování u „statických komponent“ v React funkční komponentě?
Mám React funkční komponentu, která zobrazuje seznam štítků a příspěvků + několik statických textů/dekorací. Aktuálně vybraný štítek ukládám do stavu pomocí hooku useState. Příspěvky jsou získávány pomocí Apollo hooku useQuery s proměnnou tag. Uživatel by měl být schopen vybrat štítek a ten nahradí aktuální stav tag - tím se useQuery(POSTS_QUERY) znovu spustí s novou proměnnou 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>
)
}
Má otázka je, proč se můj blok h1 stále přerenderovává, i když mu nic nepředávám? Nebo zcela nepochopil, jak React funguje?
Odpověď č. 1
Komponenty React se znovu renderují, kdykoliv se změní jejich stav nebo vlastnosti (props). Pokud čtu správně, měníte značku ve stavu pokaždé, když se změní URL, a tím způsobujete, že se komponenta sama znovu renderuje.
Odpověď č. 2
Jelikož je váš stav deklarován na vaší komponentě NewsList, jakákoli změna stavu (jak uvedl jiný uživatel ve své odpovědi) způsobí přerenderování celé komponenty (NewsList) a ne jen komponent, kterým jste předali svůj stav (tedy i statického <h1>, který tam máte).
Pokud existují části této komponenty, které s tímto stavem nesouvisí, můžete je přesunout ven, abyste se vyhnuli opětovnému vykreslení.
Avšak, v případech jako je tento, přerenderování vašeho <h1> není pro React nákladné. Měli byste se tím zabývat a následovat tento přístup u vlastních komponent, kde se dějí složitější věci (např. naplňování seznamů nebo výpočty apod.). V takových případech nechcete, aby se všechny tyto složité věci děly znovu, pokud nebyly ovlivněny změnou stavu rodiče. Také byste vždy měli zvážit, zda dává smysl komponentu přesunout ven, nebo jestli tím svůj kód zbytečně nezkomplikujete.
Vždy byste měli najít rovnováhu mezi dobře organizovaným a efektivním kódem.
