I'm using React context within Gatsby. When I'm running the app locally with gatsby develop
, things works fine. When I try Gatsby build, I get errors on the functions I'm passing via React Context.
WebpackError: TypeError: Cannot destructure property
togglePlayerof 'undefined' or 'null'.
Player Context
:
import React, { Component } from "react"
const PlayerContext = React.createContext()
export class PlayerProvider extends Component {
constructor(props) {
super(props)
this.state = {
isPlaying: false,
currentlyPlayingSoundCloudTrack: '',
drawerOpen:false
}
}
togglePlayer = show => {
if (show.id === this.state.currentlyPlayingSoundCloudTrack.id
) {
this.setState(state => ({
isPlaying: false,
currentlyPlayingSoundCloudTrack: "",
}))
} else {
this.setState(state => ({
isPlaying: true,
currentlyPlayingSoundCloudTrack: show,
}))
}
}
render() {
const { children } = this.props
console.log(this.state)
return (
<PlayerContext.Provider
value={{
togglePlayer: this.togglePlayer,
currentlyPlayingSoundCloudTrack: this.state
.currentlyPlayingSoundCloudTrack,
isPlaying: this.state.isPlaying,
}}
>
{children}
</PlayerContext.Provider>
)
}
}
export const PlayerConsumer = PlayerContext.Consumer
A gatsby template or component that wants to use the context functions
import React from "react";
import { withStyles } from "@material-ui/core/styles";
import { graphql } from "gatsby";
import { PlayerConsumer } from "../contexts/PlayerContext.js";
import { kebabCase } from "lodash";
const ItemPage = ({ data, classes }) => {
//console.log(data);
const item = data.item;
return (
<PlayerConsumer>
{({ togglePlayer, currentlyPlayingSoundCloudTrack }) => (
<div>
{typeof currentlyPlayingSoundCloudTrack !== "undefined" &&
item.id == currentlyPlayingSoundCloudTrack.id ? (
<IconButton
aria-label="Play/pause"
className={classes.iconButton}
onClick={() => togglePlayer(item)}
>
<Pause className={classes.playIcon} />
</IconButton>
) : (
<IconButton
aria-label="Play/pause"
className={classes.iconButton}
onClick={() => togglePlayer(item)}
>
<PlayArrowIcon className={classes.playIcon} />
</IconButton>
)}
</div>
)}
</PlayerConsumer>
);
};
export default withStyles(styles)(ItemPage);
Should call a function ok whether using gatsby build or develop
When running 'gatsby build' , it breaks. But works fine on gatsby develop
System:
OS: macOS 10.14
CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 12.12.0 - /usr/local/bin/node
Yarn: 1.19.1 - /usr/local/bin/yarn
npm: 6.11.3 - /usr/local/bin/npm
Languages:
Python: 2.7.10 - /usr/bin/python
Browsers:
Chrome: 78.0.3904.70
Firefox: 70.0.1
Safari: 12.0
npmPackages:
gatsby: ^2.17.7 => 2.17.7
gatsby-cli: ^2.8.8 => 2.8.8
gatsby-image: ^2.2.29 => 2.2.30
gatsby-plugin-manifest: ^2.2.25 => 2.2.26
gatsby-plugin-material-ui: ^2.1.6 => 2.1.6
gatsby-plugin-offline: ^2.0.25 => 2.2.10
gatsby-plugin-react-helmet: ^3.0.10 => 3.1.13
gatsby-plugin-remote-images: ^1.0.7 => 1.0.7
gatsby-plugin-sharp: ^2.2.32 => 2.2.33
gatsby-remark-copy-linked-files: ^2.0.11 => 2.1.28
gatsby-remark-images: ^3.0.1 => 3.1.28
gatsby-remark-relative-images: ^0.2.1 => 0.2.3
gatsby-source-filesystem: ^2.1.35 => 2.1.35
gatsby-transformer-remark: ^2.3.4 => 2.6.31
gatsby-transformer-sharp: ^2.1.9 => 2.3.1
Thank you for opening this!
This is most likely not related to Gatsby, as I can use context just fine in this codesandbox: https://codesandbox.io/s/gatsby-context-wknx8
I'd recommend asking for React advise in places like Reactiflux Discord or StackOverflow.
We're marking this issue as answered and closing it for now but please feel free to comment here if you would like to continue this discussion. We also recommend heading over to our communities if you have questions that are not bug reports or feature requests. We hope we managed to help and thank you for using Gatsby!
I solved this with defaultState
in the context provider
const defaultState = {
togglePlayer: () => {},
currentlyPlayingSoundCloudTrack: '',
isPlaying: false,
handleDrawerOpen:() => {},
handleDrawerClose:() => {},
drawerOpen:false
}
const PlayerContext = React.createContext(defaultState)
I used the default state but had to include a check as well.
<div>
{defaultState && defaultState.isPlaying ? : "Start" : "Pause"}
<div>
Most helpful comment
I solved this with
defaultState
in the context provider