React项目Context Consumer渲染多子元素报错该如何解决?
问题原因分析
触发报错的核心原因以及关联错误如下:
- Consumer语法不符合要求:React Context的
Consumer组件要求唯一子元素必须是一个函数,函数接收context的value作为参数,返回要渲染的组件。你当前直接把普通组件作为Consumer的子元素传入,不符合语法要求,是触发本次报错的直接原因。 - Context使用逻辑错误:你在
main.js中使用FoodContext.Consumer时,外层没有包裹对应的FoodProvider提供上下文值,即使语法正确也无法拿到上下文数据。 - Consumer引用错误:
App.js中你使用了FoodProvider.Consumer,实际上Consumer是挂载在你创建的FoodContext对象上的,不是挂载在Provider上的,引用来源错误。
修复步骤
步骤1:修改main.js代码
删除main.js里的FoodContext.Consumer,直接把FoodProvider套在App外层,确保App内部所有组件都能拿到上下文值:
import React from 'react' import ReactDOM from 'react-dom' import { BrowserRouter } from 'react-router-dom'; import './index.css' import App from './App' import { FoodProvider } from './components/context/FoodContext'; ReactDOM.render( <BrowserRouter> <FoodProvider> <App /> </FoodProvider> </BrowserRouter>, document.getElementById('root') )
步骤2:修改App.js代码
删除App.js里的FoodProvider.Consumer包裹,如果你需要在App内使用上下文值,直接用useContext Hook更简洁:
import {Switch, Route } from 'react-router-dom'; import { useContext } from 'react'; import {FoodContext} from "./components/context/FoodContext"; import HomePage from './components/HomePage'; import NotFound from './components/NotFound'; import Menu from './components/Menu'; import SingleFood from './components/SingleFood'; function App() { // 需要使用上下文值时打开即可,不需要可以删除这行 // const [foods, setFoods] = useContext(FoodContext); return ( <div className="App"> <Switch> <Route exact path='/' component={HomePage} /> <Route path='/menu' component={Menu } /> <Route path='/food/:id' component={SingleFood } /> <Route path='*' component={NotFound } /> </Switch> </div> ); } export default App;
步骤3:子组件使用Context的正确姿势
如果在Menu、SingleFood等子组件中需要使用上下文值,两种方式任选其一即可:
方式1:useContext Hook(推荐,代码更简洁)
import { useContext } from 'react' import { FoodContext } from './context/FoodContext' function Menu() { const [foods, setFoods] = useContext(FoodContext) // 直接使用foods、setFoods处理业务逻辑即可 return <div>菜单页面内容</div> }
方式2:Consumer写法
import { FoodContext } from './context/FoodContext' function Menu() { return ( <FoodContext.Consumer> {/* 唯一子元素必须是函数,参数就是你传入Provider的value值 */} {([foods, setFoods]) => { return <div>菜单页面内容</div> }} </FoodContext.Consumer> ) }
内容的提问来源于stack exchange,提问作者Dev_felz
相关产品推荐
相关产品推荐

