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?

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... Commented Oct 24, 2019 at 0:19

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.