我正在尝试学习Context API,并且想要实现的目标是在标题中显示“已登录”用户,并根据已登录状态操作菜单选项(存储“ isAuthenticated'处于状态?)
我的上下文类:
import React from 'react';
const Context = React.createContext();
export class Provider extends React.Component {
state = {
isAuthenticated: true,
user: {
name: "Joe Smith",
email: "joe.smith@here.com"
}
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
)
}
}
export const Consumer = Context.Consumer;
因此,非常基础。设置一个状态,稍后再在某些子组件中,我要显示章的名称。
我的App.js是正在使用的“提供程序”,因此我所有的组件都可以访问此数据:
import React from 'react';
import { HashRouter , Route, Switch } from 'react-router-dom';
import Home from './components/home';
import Header from './components/header';
import Accounts from './components/accounts';
import Reports from './components/reports';
import Login from './components/login';
import {Container} from 'reactstrap';
import { Provider } from './context';
function App() {
return (
<div className="App">
<Provider>
<HashRouter>
<Header />
<Container>
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/accounts" component={Accounts} />
<Route exact path="/reports" component={Reports} />
<Route exact path="/login" component={Login} />
</Switch>
</Container>
</HashRouter>
</Provider>
</div>
);
}
export default App;
因此,在这种情况下,“标题”需要访问我的上下文。 我的页眉将显示一个菜单(基于我将添加到上下文中的一些信息,该菜单将显示或隐藏选项,登录按钮等)。
在菜单下,我想显示一个小的信息栏。例如,登录用户名。因此,我的标头类如下:
import React from 'react';
import Menu from './menu';
import InfoBar from './infobar';
import { Consumer } from '../context';
class Header extends React.Component {
render() {
const menuStyle = {
paddingBottom: "5px"
}
return(
<Consumer>
<div style={menuStyle}>
{value => {
console.log(value);
return (
<h1>Test</h1>
)
}}
<Menu />
<InfoBar />
</div>
</Consumer>
)
}
}
export default Header;
但是问题现在发生了。当我运行我的代码时,它会编译并运行,但是立即出现运行时错误:
TypeError:render不是函数updateContextConsumer C:/Storage/Scratch/ReactApp/accufinance/node_modules/react-dom/cjs/react-dom.development.js:16082
我读到一些有关退货和多个孩子的信息,但是我的代码似乎没有这个问题。在理解问题和问题发生的地方提供的任何帮助都是很好的。如果我注释掉“标题”中的代码,则没有错误...但是...也没有屏幕。它似乎正在该地区发生。
答案 0 :(得分:3)
如果您正在使用功能组件并将 useContext
与 createContext
一起使用,您可能会忘记在渲染之前添加“Provider”,例如 myContext.Provider
在我的情况下我通常会忘记 .Provider
并且只写 <myContext></myContext>
而我必须这样做... <myContext.Provider></myContext.Provider>
答案 1 :(得分:2)
上下文使用者使用渲染道具,特别是函数作为子组件,因此它希望其直接子对象是函数(而不是组件)。就您而言,您只需将div移入函数内即可:
<Consumer>
{value => {
console.log(value);
return (
<div style={menuStyle}>
<h1>Test</h1>
<Menu />
<InfoBar />
</div>
)
}}
</Consumer>
当您想将组件的内部状态展示给子组件时,但又想与其他类型的子组件一起使用时,渲染道具确实非常强大。
模式如下:
class Parent extends Component {
state = { name: 'Mike' }
handleChange = (e) => this.setState({ name: e.target.value })
render() {
// Here's the main difference: We expect `children` to be
// a function, and we pass name in as the argument
return children(state.name);
}
}
const InputChild = props => <input value={props.name} />
const HeaderChild = props => <h1>{props.name}</h1>
const App = () => {
return (
<Parent>
{name => {
// We could easily swap in `HeaderChild` here (or
// anything else!), passing `Parent`'s internal
// state.name to it instead:
<InputChild name={name} />
}
</Parent>
)
}
这是使Context工作的原因,因为消费者对其子组件没有任何了解,但是可以公开其状态(这是提供者的值)。
React文档中有很多关于渲染道具的部分:https://reactjs.org/docs/render-props.html