Реагирующий контекст и ошибка типа поставщика: переменная не определена

#javascript #reactjs #chakra-ui

#javascript #reactjs #чакра-пользовательский интерфейс

Вопрос:

Я пытаюсь создать такую кнопку, чтобы при нажатии изменялся контекст реакции. То есть мой контекст состоит только из списка строк, который заполняется при успешном выполнении запроса GET. Пример ответа следующий:

 {
  "message": "OK",
  "status-code": 200,
  "data": {
    "models": [
      "model1",
      "model2",
      "model3"
    ]
  }
}
 

Код, касающийся обновления моего контекста, следующий:

 import React from 'react'
import {
    VStack,
    Button,
    OrderedList,
    ListItem
} from '@chakra-ui/react'

const Endpoint = 'http://localhost:5000/'

const ModelsContext = React.createContext([])

function Models() {
    const [models, setModels] = React.useContext(ModelsContext)
    const updateModels = async () => {
        await fetch(Endpoint   'models', {
            method: 'GET',
            headers: {
                Accept: 'application/json'
            }
        })
        .then((resp) => resp.json())
        .then(function(data) {
            setModels(data.models)
        })
    }

    return (
        <VStack>
            <Button
                size="sm"
                colorScheme='teal'
                variant='solid'
                onClick={updateModels}>
            Get Models List
            </Button>
            <ModelsContext.Provider value={{models}}>
                <OrderedList>
                {
                    models.map((name) => (
                        <ListItem>
                            {name}
                        </ListItem>
                    ))
                }
                </OrderedList>
            </ModelsContext.Provider>
        </VStack>
    )
}

export default Models
 

Мне также нужно показать результаты в виде упорядоченного списка Chakra-UI. Однако models переменная остается неопределенной внутри <OrderedList /> блока, даже если я определил контекстный блок React Provider.
Фактическая ошибка, которую я получаю, такова: «Ошибка типа: модели не определены» в позиции <OrderedList> .

Заранее благодарю вас!

Ответ №1:

Вы неправильно используете контекст. Контекст предназначен для передачи значений дочерним элементам без детализации реквизита. Это отлично подходит, если у вас есть глубоко вложенные дочерние элементы, которые полагаются на одни и те же переменные. Таким образом, вам не нужно передавать их в качестве реквизитов, вы можете просто захватить их с помощью useContext хука. Вот пример того, как использовать контекст:

 const Endpoint = 'http://localhost:5000/'

const ModelsContext = createContext([])

function ModelsContextProvider({children}) {
  const [models, setModels] = useState([])
  
  return (
    <ModelsContext.Provider value={{models, setModels}}>
      {children}
    </ModelsContext.Provider>
  )
}

function Models() {
  const { models, setModels } = useContext(ModelsContext)

  const updateModels = async () => {
    await fetch(Endpoint   'models', {
        method: 'GET',
        headers: {
            Accept: 'application/json'
        }
    })
    .then((resp) => resp.json())
    .then(function(data) {
        setModels(data.models)
    })
  }

  return (
    <VStack>
        <Button
            size="sm"
            colorScheme='teal'
            variant='solid'
            onClick={updateModels}>
        Get Models List
        </Button>
          <OrderedList>
            {
                models.map((name) => (
                    <ListItem>
                        {name}
                    </ListItem>
                ))
            }
          </OrderedList>
    </VStack>
  )
}

export default function App() {
  return (
    <ModelsContextProvider>
      <Models />
    </ModelsContextProvider>
  );
}
 

В приведенном выше примере вы устанавливаете значение контекста со значением состояния. Таким образом, вы можете useState использовать хук в качестве вашего сеттера для контекста. В вашем примере вам не нужен контекст, вы можете просто использовать useState хук.

 const Endpoint = 'http://localhost:5000/'

function Models() {
    const [models, setModels] = React.useState([])
    const updateModels = async () => {
        await fetch(Endpoint   'models', {
            method: 'GET',
            headers: {
                Accept: 'application/json'
            }
        })
        .then((resp) => resp.json())
        .then(function(data) {
            setModels(data.models)
        })
    }

    return (
        <VStack>
            <Button
                size="sm"
                colorScheme='teal'
                variant='solid'
                onClick={updateModels}>
            Get Models List
            </Button>
                <OrderedList>
                {
                    models.map((name) => (
                        <ListItem>
                            {name}
                        </ListItem>
                    ))
                }
                </OrderedList>

        </VStack>
    )
}

export default Models
 

Комментарии:

1. Я только что увидел, что я оставил функцию <ModelsContext.Provider> в моделях. В этом нет необходимости. Просто подумал, что я дам вам знать, если вы еще не поняли этого. Я отредактировал свой ответ, чтобы отразить это. Я просто копировал и вставлял, а затем рефакторил ваш код и пропустил его.

Ответ №2:

Вы должны обернуть модели <ModelsContext.Provider value={{models}}> , а затем внутри моделей useContext будет возвращено значение от поставщика.

Смотрите Пример в документе

Комментарии:

1. Я попытался обернуть все внутри ModelsContext.Provider value={{models}} , но у меня все та же проблема.

2. const {models} = React.useContext(ModelsContext). Для установки значений используйте useState в родительском компоненте