尝试使用上下文API时看到“渲染不是函数”

时间:2019-06-13 00:10:34

标签: javascript reactjs

我正在尝试学习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

我读到一些有关退货和多个孩子的信息,但是我的代码似乎没有这个问题。在理解问题和问题发生的地方提供的任何帮助都是很好的。如果我注释掉“标题”中的代码,则没有错误...但是...也没有屏幕。它似乎正在该地区发生。

2 个答案:

答案 0 :(得分:3)

如果您正在使用功能组件并将 useContextcreateContext 一起使用,您可能会忘记在渲染之前添加“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