看到“渲染不是函数"尝试使用 Context API 时 [英] Seeing "render is not a function" when trying to use Context API

查看:67
本文介绍了看到“渲染不是函数"尝试使用 Context API 时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习 Context API,我想要实现的是在我的标题中显示登录用户,以及根据登录状态操作我的菜单选项(存储 ' 是否安全?isAuthenticated' 状态?)

我的上下文类:

从'react'导入React;const Context = React.createContext();导出类 Provider 扩展 React.Component {状态 = {isAuthenticated: 真,用户:{姓名:乔·史密斯",电子邮件:joe.smith@here.com"}}使成为() {返回 (<Context.Provider value={this.state}>{this.props.children}</Context.Provider>)}}出口const消费者= Context.Consumer;

所以,非常基础.设置一个状态,以后在一些子组件中,我想显示chaps名称.

我的 App.js 是使用 'Provider',所以我的所有组件都可以访问这些数据:

从'react'导入React;import { HashRouter , Route, Switch } from 'react-router-dom';从 './components/home' 导入 Home;从'./components/header'导入标题;从./components/accounts"导入帐户;从./components/reports"导入报告;从'./components/login'导入登录;从'reactstrap'导入{Container};从 './context' 导入 { Provider };功能应用(){返回 (<div className="应用程序"><提供者><HashRouter><标题/><容器><开关><路由精确路径="/" component={Home}/><路由精确路径="/accounts" component={Accounts}/><路由精确路径="/reports" component={Reports}/><路由精确路径="/login" component={Login}/></开关></容器></HashRouter></提供者>

);}导出默认应用程序;

所以在这种情况下,'Header' 需要访问我的上下文.我的标题将显示一个菜单(根据我将添加到上下文中的一些信息,该菜单将显示或隐藏选项、登录按钮等).

在菜单下,我想显示一个小信息栏.例如,登录用户名.所以,我的头类看起来像这样:

从'react'导入React;从'./menu'导入菜单;从./infobar"导入信息栏;从'../context'导入{消费者};类头扩展 React.Component {使成为() {const menuStyle = {paddingBottom: "5px"}返回(<消费者><div style={menuStyle}>{值=>{控制台日志(值);返回 (<h1>测试</h1>)}}<菜单/><信息栏/>

</消费者>)}}导出默认标题;

但问题现在发生了.当我运行我的代码时,它会编译并运行,但立即出现运行时错误:

<块引用>

TypeError: render 不是函数 updateContextConsumerC:/Storage/Scratch/ReactApp/accufinance/node_modules/react-dom/cjs/react-dom.development.js:16082

我阅读了有关返回和多个子项的内容,但我的代码似乎没有这个问题.任何有助于理解问题和问题发生位置的帮助都会很棒.如果我注释掉 'header' 中的代码,没有错误......但是......也没有屏幕.它似乎发生在该地区.

解决方案

Context Consumer 使用一个 render prop,特别是一个函数作为子组件,所以它期望它的直接子组件是一个函数(而不是一个组件).在您的情况下,您可以在函数内移动 div:

<消费者>{值=>{控制台日志(值);返回 (<div style={menuStyle}><h1>测试</h1><菜单/><信息栏/>

)}}</消费者>

当您想将组件的内部状态公开给其子项,但同时又想将其与不同类型的子项一起使用时,渲染道具非常强大.

模式是这样的:

class Parent extends Component {状态 = { 名称:'迈克'}handleChange = (e) =>this.setState({ name: e.target.value })使成为() {//这是主要的区别:我们希望 `children` 是//一个函数,我们将名称作为参数传入返回孩子(state.name);}}const InputChild = props =><输入值={props.name}/>const HeaderChild = 道具 =><h1>{props.name}</h1>const App = () =>{返回 (<家长>{名称=>{//我们可以很容易地在这里交换`HeaderChild`(或//其他任何东西!),传递 `Parent` 的内部//state.name 改为:<InputChild name={name}/>}</父母>)}

这就是使 Context 工作的原因,因为消费者对其子级中的组件一无所知,但它可以公开其状态(即来自提供者的值).

React 文档有一个关于渲染道具的很棒的部分:https://reactjs.org/docs/render-props.html

I'm trying to learn the Context API, and what I want to achieve, is showing the Logged In user in my header, as well as manipulate my menu options based on the logged in state (Is it safe to store 'isAuthenticated' in state?)

My context class:

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;

So, extremely basic. Sets up a state, and in some child components later, I want to display the chaps name.

My App.js is the using 'Provider', so that all my components have access to this data:

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;

So in this case, 'Header' needs access to my context. My Header will show a menu (which, based on some info I'll add to the context, will show or hide options, login buttons etc).

Under the menu, I want to show a small info bar. Logged in user name, for example. So, my header class looks like this:

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;

But the problem now happens. When I run my code, it compiles and runs, but right away, I get a runtime error:

TypeError: render is not a function updateContextConsumer C:/Storage/Scratch/ReactApp/accufinance/node_modules/react-dom/cjs/react-dom.development.js:16082

I read something about returns and multiple children, but my code seems to not have that issue. Any assistance with understanding the issue and where the problem is happening would be great. If I comment out the code in 'header', no error... but... no screen either. It seems to be occuring in the area.

解决方案

The Context Consumer uses a render prop, specifically a function as a child component, so it expects its immediate child to be a function (not a component). In your case, you can just move the div inside the function:

<Consumer>
  {value => {
    console.log(value);
    return (
      <div style={menuStyle}>
        <h1>Test</h1>
        <Menu />
        <InfoBar />     
      </div>
    )
  }}
</Consumer>

Render props are really powerful for when you want to expose a component's internal state to its children, but when you also want to use it with different types of children.

The pattern is like this:

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>
  )
}

This is what makes Context work, because the Consumer doesn't have any knowledge of the components in its children, but it can expose its state (which is the value from the Provider).

The React docs have a great section on render props: https://reactjs.org/docs/render-props.html

这篇关于看到“渲染不是函数"尝试使用 Context API 时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆