Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Next.JS -- getInitialProps to pass props and state to child components via ContextProvider

I am using getInitialProps() in _App.js to grab some api data and I want to pass that data down as props to my other components via React Context. I want to initialize the Context Provider with state via the constructor.

First I initialize context via createContext().

config/Context.js:

import { createContext } from 'react';
const Context = createContext();
export default Context;

Then I create Context.Provider in its own component using constructor to initialize state.

provider/ContextProvider.js:

import React, { Component } from 'react';
import Context from '../config/Context';

class ContextProvider extends Component {
  constructor(props) {
    super(props);
    
    this.state = {
      filters: {
        active: true,
        headerActive: false
      }
    };
  }

  render() {
    return (
      <Context.Provider>
        {this.props.children}
      </Context.Provider>
    );
  }
}

export default ContextProvider;

In _app.js I make an API call within getInitialProps() and pass that data into the Context Provider.

pages/_app.js

import App, { Container } from 'next/app';
import ContextProvider from '../provider/ContextProvider';
import fetch from 'isomorphic-unfetch';

export default class MyApp extends App {
  static async getInitialProps() {
    const res = await fetch('https://node-hnapi.herokuapp.com/news');
    let data = await res.json();

    console.log(data)
    return { articles: data }
  }

  render () {
    const { Component, pageProps } = this.props;
    
    return (
      <Container>
        <ContextProvider value={{ articles: this.props.articles}}>
          <Component {...pageProps} />
        </ContextProvider>
      </Container>
    );
  }
}

At this point I assume that I would have access to context via Context.Consumer or a hook like useContext() but context is undefined in the following component:

components/ArticleList.js:

import React from 'react';
import Context from '../config/Context';

const ArticleList = () => {
  const generateArticles = () => {
    const context = React.useContext(Context);
    console.log(context, 'context') // Context is undefined here
    // return context.articles.map(article => <p>{article.title}</p>)
    // Error: Cannot read property 'articles' because context is undefined
  }

  return (
    <div>
      <h3>Article List</h3>
      {generateArticles()}
    </div>
  );
};

export default ArticleList;

Why is context undefined in components/ArticleList.js? I tried passing context into the component via Context.Consumer and I got the same result.

Here is repo replicating the issue: https://github.com/joelhoelting/next-context-api-test

like image 928
Joel Hoelting Avatar asked Mar 05 '23 07:03

Joel Hoelting


1 Answers

In ContextProvider.js you forget to pass value to Context.Provider

import React, { Component } from 'react';
import Context from '../config/Context';

class ContextProvider extends Component {
  constructor(props) {
    super(props);

    this.state = {
      filters: {
        active: true,
        headerActive: false
      }
    };
  }

  render() {
    const { value } = this.props
    return (
      <Context.Provider value={ value }>
        {this.props.children}
      </Context.Provider>
    );
  }
}

export default ContextProvider;
like image 192
evgeni fotia Avatar answered Mar 06 '23 20:03

evgeni fotia