Почему `useContext` не перерисовывает мой компонент? - PullRequest
0 голосов
/ 20 января 2020

Согласно документам :

Когда обновится ближайший <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
  }
}

Ответы [ 2 ]

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

Вам не нужно использовать как <Context.Consumer>, так и useContext hook.

Используя хук useContext, вы получаете доступ к значению, хранящемуся в Context.

Что касается вашего конкретного примера c, лучший способ использовать Context в вашем компоненте Visuals будет быть следующим:

import React, { useContext } from "react";
import Context from "./context";

const Visuals = () => {
  const filterByYear = "year";
  const filterByTheme = "theme";

  const { data, set } = useContext(Context);
  const { filterBy, isOptionClicked, filterValue } = data;

  const works =
    filterBy === filterByYear
      ? "filter nodes by year"
      : "filter nodes by theme";

  return (
    <div noFooter="true">
      <div>
        {data.filterBy === filterByYear ? <h1>Year</h1> : <h1>Theme</h1>}
        the value for the 'works' variable is: {works}
        <button onClick={() => set({ filterBy: "theme" })}>
          Filter by theme
        </button>
        <button onClick={() => set({ filterBy: "year" })}>
          Filter by year
        </button>
      </div>
    </div>
  );
};

export default Visuals;

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

Вы можете посмотреть рабочий пример с приведенной выше реализацией useContext, которая несколько похожа на ваш пример в этой песочнице

надеюсь, это поможет.

0 голосов
/ 21 января 2020

Проблема была смущающе простой - <Visuals> было выше в дереве компонентов, чем <Layout, по какой-то причине я все еще пытаюсь решить. Отмечу ответ Итая как правильный, потому что он наиболее близок к выяснению обстоятельств с учетом обстоятельств

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...