React Context and Provider - TypeError: variable is undefined

React Context and Provider - TypeError: variable is undefined

我正在尝试创建一个按钮,以便在按下时修改 React 上下文。 也就是说,我的上下文仅包含一个字符串列表,该列表在 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 有序列表。但是,即使我定义了 React Provider Context 块,models 变量在 <OrderedList /> 块内仍未定义。 我得到的实际错误是:位置 <OrderedList>.

中的“TypeError: models is undefined”

提前致谢!

您应该将模型包装在 <ModelsContext.Provider value={{models}}> 中,然后在模型内部 useContext 将 return 来自提供商的值。

参见 doc

中的示例

您没有正确使用上下文。上下文用于将值传递给 children 而无需钻井。如果您有依赖相同变量的深层嵌套 children,这非常有用。这样你就不必将它们作为 props 传递下去,你可以使用 useContext 钩子来获取它们。以下是如何使用 Context 的示例:

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 挂钩充当上下文的 setter。在您的示例中,您不需要上下文,您可以只使用 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