Согласно документам :
Когда обновится ближайший <MyContext.Provider>
над компонентом, этот хук вызовет повторное рендеринг с последним значением контекста, переданным этому провайдеру MyContext , Даже если предок использует React.memo
или shouldComponentUpdate
, повторное рендеринг все равно произойдет, начиная с самого компонента с использованием useContext. ... Компонент, вызывающий useContext, всегда будет перерисовываться при изменении значения контекста.
В моем проекте Gatsby JS я определяю свой контекст следующим образом:
Контекст. js
import React from "react"
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
set: () => {},
}
const Context = React.createContext(defaultContextValue)
class ContextProviderComponent extends React.Component {
constructor() {
super()
this.setData = this.setData.bind(this)
this.state = {
...defaultContextValue,
set: this.setData,
}
}
setData(newData) {
this.setState(state => ({
data: {
...state.data,
...newData,
},
}))
}
render() {
return <Context.Provider value={this.state}>{this.props.children}</Context.Provider>
}
}
export { Context as default, ContextProviderComponent }
В макете. js Файл, который охватывает несколько компонентов, помещаю провайдер контекста:
Макет. js :
import React from 'react'
import { ContextProviderComponent } from '../../context'
const Layout = ({children}) => {
return(
<React.Fragment>
<ContextProviderComponent>
{children}
</ContextProviderComponent>
</React.Fragment>
)
}
И в компоненте, который я sh использую для контекста:
import React, { useContext } from 'react'
import Context from '../../../context'
const Visuals = () => {
const filterByYear = 'year'
const filterByTheme = 'theme'
const value = useContext(Context)
const { filterBy, isOptionClicked, filterValue } = value.data
const data = <<returns some data from backend>>
const works = filterBy === filterByYear ?
data.nodes.filter(node => node.year === filterValue)
:
data.nodes.filter(node => node.category === filterValue)
return (
<Layout noFooter="true">
<Context.Consumer>
{({ data, set }) => (
<div onClick={() => set( { filterBy: 'theme' })}>
{ data.filterBy === filterByYear ? <h1>Year</h1> : <h1>Theme</h1> }
</div>
)
</Context.Consumer>
</Layout>
)
Context.Consumer
, работает должным образом, поскольку он успешно обновляется и отражает изменения в контексте. Однако, как видно из кода, я хотел бы иметь доступ к обновленным значениям контекста в других частях компонента, то есть вне функции return
, где исключительно используется Context.Consumer
. Я предположил, что использование хука useContext
поможет в этом, поскольку мой компонент будет перерисовываться с новыми значениями из контекста каждый раз, когда щелкает div - однако это не так. Любая помощь, выясняющая, почему это так, будет оценена.
TL; DR: <Context.Consumer>
обновляет и отражает изменения контекста дочернего компонента, useContext
этого не делает, хотя компонент нуждается в этом.
ОБНОВЛЕНИЕ: Теперь я выяснил, что useContext
будет считывать значение контекста по умолчанию, переданное в createContext
, и по существу будет работать независимо от Context.Provider
. Вот что здесь происходит, Context.Provider
включает метод, который изменяет состояние, тогда как значение контекста по умолчанию - нет. Моя задача сейчас - найти способ включить функцию в значение контекста по умолчанию, которая может изменять другие свойства этого значения.
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
set: () => {}
}
set
- это пустая функция, определенная в ContextProviderComponent
(см. Выше). Как я могу (если возможно) определить его непосредственно в значении контекста, чтобы:
const defaultContextValue = {
data: {
filterBy: 'year',
isOptionClicked: false,
filterValue: ''
},
test: 'hi',
set: (newData) => {
//directly modify defaultContextValue.data with newData
}
}