React Context and Next JS
Asked Answered
T

1

6

I'm trying to add simple React Context to my app. I create Context in "./components/DataProvider.js" that looks like this:

import React, { Component } from 'react'

const DataContext = React.createContext()

class DataProvider extends Component {
    state = {
        isAddButtonClicked: false
    }

    changeAddButtonState = () => {
        if( this.state.isAddButtonClicked ) {
            this.setState({
                isAddButtonClicked: false
            })
        } else {
            this.setState({
                isAddButtonClicked: true
            })            
        }
    }

    render() {
        return(
            <DataContext.Provider
                value={{
                    isAddButtonClicked: this.state.isAddButtonClicked,
                    changeAddButtonState: () => {
                        if( this.state.isAddButtonClicked ) {
                            this.setState({
                                isAddButtonClicked: false
                            })
                        } else {
                            this.setState({
                                isAddButtonClicked: true
                            })            
                        }
                    }
                }}
            >
                {this.props.children}
            </DataContext.Provider>
        )
    }

}

const DataConsumer = DataContext.Consumer

export default DataProvider
export { DataConsumer }

Which then I added to "./pages/_app.js"

import App, { Container } from 'next/app'

import DataProvider from '../components/DataProvider'

class MyApp extends App {
render () {
    const { Component, pageProps } = this.props
    return (
    <Container>
        <DataProvider>
        <Component {...pageProps} />
        </DataProvider>
    </Container>
    )
}
}

export default MyApp

And consume it in "./components/AddPostButton.js".

import React, {Component} from 'react'
import { DataConsumer } from './DataProvider'

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'

class AddPostButton extends Component {
    render() {
        return (
            <div>
                <DataConsumer>
                    {({ changeAddButtonState }) => (
                        <a onClick={changeAddButtonState}>
                            <FontAwesomeIcon icon={faPlus} color='#fff' />
                        </a>
                    )}
                </DataConsumer>
            </div>

        )
    }

}

export default AddPostButton

But I get this error "Cannot read property 'changeAddButtonState' of undefined". I'm using React 16.7 and NextJS 7.0.2. Don't know what is wrong.

The second question is should I use one Context for everything or just use them as Model in MVC pattern?

Taperecord answered 24/1, 2019 at 20:14 Comment(1)
I'm learning next.js as well. Since I couldn't figure out why the code won't work, I just tried your code above (with a single AddPostButton added to index.js) and it seems to work for me just fine. With a console.log in the callback I could see it being printed in the browser. Changing the data provider to use changeAddButtonState: this.changeAddButtonState also seems to work just fine. This is node: 12.12.0, next: 9.1.1, react 16.10.2, react-dom 16.10.2...Rhinal
T
5

I fixed it by moving changeAddButtonState to Context Component state so my DataProvider.js now looks like this

import React, { Component } from 'react'

const DataContext = React.createContext()

class DataProvider extends Component {
    state = {
        isAddButtonClicked: false,
        changeAddButtonState: () => {
            if (this.state.isAddButtonClicked) {
                this.setState({
                    isAddButtonClicked: false
                })
            } else {
                this.setState({
                    isAddButtonClicked: true
                })
            }
        }
    }

    render() {
        return(
            <DataContext.Provider
                value={this.state}
            >
                {this.props.children}
            </DataContext.Provider>
        )
    }

}

const DataConsumer = DataContext.Consumer

export default DataProvider
export { DataConsumer }

And then in AddButton component I changed code to look like this

import React, {Component} from 'react'
import { DataConsumer } from './DataProvider'

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'

class AddPostButton extends Component {
    constructor(props) {
        super(props)
    }

    render() {
        return (
            <div>
                <DataConsumer>
                    {(context) => (
                        <a onClick={context.changeAddButtonState}>
                            <FontAwesomeIcon icon={faPlus} color='#fff' />
                        </a>
                    )}
                </DataConsumer>
            </div>

        )
    }

}

export default AddPostButton
Taperecord answered 24/1, 2019 at 21:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.