window is not defined server side rendering(react + express) - javascript

If the browser URL is requested, routing works normally.
By the way, location = ${path};
The part that says Component An error occurs when calling react renderToString function.
I'm looking at web pack settings or something, but I can't find the cause. Help!
// App.js
import React, {useState, useEffect} from 'react';
import moment from "moment";
import Header from "./components/header/Header";
import Footer from "./components/footer/Footer";
export default function App() {
const [time, setTime] = useState(null);
useEffect(() => {
console.log('use effect..');
setTime(moment().format('hh:mm:ss a'));
}, []);
return (
<div style={{height:'100%'}}>
<Header/>
<div style={{height:'100%'}}>
<h1>Sample App</h1>
<p>Current time is {time}</p>
</div>
<Footer/>
</div>
)
}
// Header.js
import React from 'react';
export default function Header() {
function goPage(path) {
console.log(`goPage..`);
console.log(window.location); // error
// window.location = path;
}
return (
<header style={{width: '100%', border: '1px dotted black'}}>
<div>
<span style={{padding: '4px'}}>My App |</span>
<span style={{padding: '4px', cursor: 'pointer'}}>Home</span>
<span style={{padding: '4px', cursor: 'pointer'}} onClick={goPage('/about')}>About</span>
</div>
</header>
)
}
server.js
const express = require('express');
const path = require('path');
import React from 'react';
import ReactDOMServer from 'react-dom/server';
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const config = require('../webpack.config.js');
const compiler = webpack(config);
import Router from '../routes/index';
import App from '../src/App';
import Html from "../src/Html";
const expressApp = express();
const port = process.env.PORT || 3000;
if (process.env.NODE_ENV != 'production') {
expressApp.use(webpackDevMiddleware(compiler, {
publicPath: '/'
}));
}
expressApp.use(express.static(path.join(__dirname, '')));
expressApp.get('*', (request, response) => {
console.log('request.. in express');
console.log(Router.match(request));
const component = ReactDOMServer.renderToString(Router.match(request));
const html = ReactDOMServer.renderToStaticMarkup(<Html
title="Sample Title"
description="Isomorphic web application sample"
body={component}
/>);
response.send(`<!DOCTYPE html>` + html);
});
expressApp.listen(port, () => {
console.log(`App is listening at http://localhost:${port}/`);
});
// Router
import React from 'react';
import App from "../src/App";
import NotFound from "../src/components/error/NotFound";
import Error from "../src/components/error/Error";
import About from "../src/components/about/About";
const routes = [
{name : 'home', path : '/', action : () => <App/>},
{name : 'about', path : '/about', action : () => <About/>},
{name : '404', path : '/404', action : () => <NotFound/>},
{name : '500', path : '/500', action : () => <Error/>},
];
export default {
match(location) {
console.log(location.path);
const route = routes.find(x => x.path === location.path);
if (route) {
try {
return route.action();
} catch (err) {
console.log('err');
return routes.find(x => x.path === '/500').action();
}
} else {
console.log('404');
return routes.find(x => x.path === '/404').action();
}
}
}
// webpack config
const path = require('path');
// plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
// SSR
const ssr = {
mode : 'development',
entry: './server/server.js',
output: {
path: path.join(__dirname, '/build'),
filename: "server.js",
},
target: 'node',
node: false,
externals: [nodeExternals()],
resolve: {
modules: ['node_modules']
},
module: {
rules: [
{
test: /(.js|.jsx)/,
exclude: /node_modules/,
include: [
path.join(__dirname, '/src'),
path.join(__dirname, '/routes/index.js'),
path.join(__dirname, '/server/server.js'),
],
use: {
loader: 'babel-loader'
}
},
]
},
plugins: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['build']
})
],
};
// CSR
const csr = {
mode : 'development',
entry:'./client/client.js',
output: {
publicPath: '/',
path: path.join(__dirname, '/build'),
filename: 'client.js'
},
target: 'web',
module: {
rules: [
{
test: /(.js|.jsx)/,
exclude: /node_modules/,
include: [
path.join(__dirname, '/src'),
path.join(__dirname, '/routes/index.js'),
path.join(__dirname, '/client/client.js'),
],
use: {
loader: 'babel-loader'
}
},
]
},
// devtool: 'source-map',
plugins: [
new MomentLocalesPlugin({
localesToKeep: ['es-us', 'ru'],
}),
]
};
module.exports = [ssr, csr];
The server is composed of express, and is set to babel7 and webpack4.
If you look at the server.js part, you get the corresponding react component in the request URL.
If renderToString() is called on the obtained component, an error of window is not defined occurs.
I really want to solve it. Please help.

Why window is not defined in SSR
On the ssr there is no definition for window. Because window is a browser based property.
you need to do something to avoid that. e.g
function goPage(path) {
console.log(`goPage..`);
if (window) {
console.log(window.location);
}
}
and on the server side you can get the url by this
req.url
// or
app.get('/users/:userId/books/:bookId', function (req, res) {
console.log(req.params)
}

Related

Import JSX file into webpack config

I am trying to import a JSX file into my webpack config. It appears the file imports, but I cannot import modules into that file. I continuously get an error saying Cannot use import statement outside a module
Here is my webpack.config.js:
const bodyParser = require('body-parser')
require('#babel/register')
const render = require('../src/static/render.jsx')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require('path');
const PATHS = {
app: path.join(__dirname, '../src/static'),
build: path.join(__dirname, '../src/static_dist')
};
const basePath = path.resolve(__dirname, '../src/static/');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
output: {
filename: '[name].js',
path: PATHS.build,
publicPath: '/static/'
},
devServer: {
before: function(app) {
app.use(bodyParser.json({ limit: '10mb' }))
app.post('/render', function (req, res) {
res.sendStatus(204);
const initialState = {} //buildInitialState(req.body)
const result = render(url, initialState)
res.json({
html: result.html,
finalState: result.finalState
})
});
},
// Render.jsx
require('#babel/register');
import React from 'react' <-- error happens here
import { Provider } from 'react-redux'
import { match, RouterContext } from 'react-router'
import ReactDOMServer from 'react-dom/server'
import configureStore from './store/configureStore';
import { createBrowserHistory } from "history";
import { routes } from "../routes.js";
import AdminNavbar from "./components/Navbars/AdminNavbar.jsx";
import Sidebar from "./components/Sidebar/Sidebar.jsx";
export default function render (url, initialState) {
... a function ...
}
I feel like I have tried everything! Tinkering with babel, adding #babel/register, adding a .babelrc, changing how it is imported, etc.
You likely need to tell Webpack to resolve that particular extension.
Here's the documentation on resolve: Resolve
The code:
module.exports = {
//...
resolve: {
extensions: ['.js', '.jsx']
}
};
Also I notice you haven't specified your entry. If the solution above doesn't work, try specifying the following:
module.exports = {
//...
entry: './src/Render.jsx'
};
Docs: Entry Point
You likely have to do both.

React useState is undefined working with webpack-dev-server

I am building a simple react app with React hooks and webpack-dev-server. I would like to enable hot reload.
Running the webpack-dev-server --mode development, I got an error: TypeError: Object(...) is not a function and It complains at the folloing line which is compiled.
var _useState = Object(react__WEBPACK_IMPORTED_MODULE_0__["useState"])(0),
This is my code
webpack.config.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './src/index.jsx',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx'],
mainFiles: ['index']
},
output: {
path: path.join(__dirname, 'public'),
publicPath: '/',
filename: 'bundle.js'
},
plugins: [new webpack.HotModuleReplacementPlugin()],
devServer: {
contentBase: './public',
hot: true
}
};
.babelrc
{
"presets": [
"#babel/preset-env",
"#babel/preset-react"
],
"plugins": [
"react-hot-loader/babel"
]
}
Body.jsx
import React, { useState } from 'react';
const Body = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>{`You clicked ${count} times`}</p>
<button type="button" onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
};
export default Body;
App.jsx
import React from 'react';
/* eslint-disable import/no-extraneous-dependencies */
import { hot } from 'react-hot-loader/root';
import { setConfig } from 'react-hot-loader';
import Body from './Body';
const App = () => (
<div className="App">
<Body />
</div>
);
export default hot(App);
index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
ReactDOM.render(<App />, document.getElementById('app'));
For dependencies, I am using react and react-dom with version 16.7.0-alpha.2.
react-hot-loader is version 4.6.3
Sadly react-hot-loader is not compatible with hooks, atleast to my knowledge and their issue github page.
https://github.com/gaearon/react-hot-loader/issues/1088

Why does isomorphic-style-loader throw a TypeError: Cannot read property 'apply' of undefined when being used in unison with CSS-Modules

I'm currently trying to render the application on the server, which works for the HTML and JS, but found that my styles (.less | .scss) would not load. I did some research and figured, not sure, that I was missing the isomorphic-style-loader in my Webpack configuration based on others running into the same issues. I set it up, at least how I understood it, but am now finding that when running the application I receive the following error:
TypeError: Cannot read property 'apply' of undefined at WithStyles.componentWillMount
I'm somewhat new to the whole React / Express thing but have been trying to follow along with tutorials and learning as I go, if anything seems out of place, please excuse me. I am hoping to see if anybody can explain what exactly causes this error, and provide me with some idea of what I could follow to resolve this error. Below is some example code that resembles the one I am having issues with, if it helps in any way.
(For reference I was following Tyler McGinnis React Router Server Rendering tutorial and tried to expand upon it to add styling - Link Here)
Thanks beforehand for any explanation provided as to what may be causing this error.
webpack.config.babel.js
import path from 'path'
import webpack from 'webpack'
import nodeExternals from 'webpack-node-externals'
const paths = {
browser: path.join(__dirname, './src/browser'),
server: path.join(__dirname, './src/server'),
build: path.resolve(__dirname, 'public')
}
let browserConfig = {
entry: `${paths.browser}/index.js`,
output: {
path: paths.build,
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.s?(a|c)ss$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.less$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
'postcss-loader'
]
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.DefinePlugin({
__isBrowser__: true
})
],
resolve: {
extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
}
}
let serverConfig = {
entry: `${paths.server}/index.js`,
target: 'node',
externals: [nodeExternals()],
output: {
path: __dirname,
filename: 'server.js',
publicPath: '/'
},
module: {
rules: [
{
test: /\.s?(a|c)ss$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
'sass-loader',
'postcss-loader'
]
}, {
test: /\.less$/,
use: [
'isomorphic-style-loader',
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: '[name]__[local]___[hash:base64:5]',
sourceMap: true
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true
}
},
'postcss-loader'
]
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.DefinePlugin({
__isBrowser__: false
})
],
resolve: {
extensions: ['.js', '.jsx', '.json', '.css', '.scss', '.sass', '.less']
}
}
module.exports = [browserConfig, serverConfig]
server.js
import express from "express"
import cors from "cors"
import React from "react"
import bodyParser from 'body-parser'
import serialize from "serialize-javascript"
import { renderToString } from "react-dom/server"
import { StaticRouter, matchPath } from "react-router-dom"
import App from '../shared/App'
import routes from '../shared/routes'
const app = express()
const port = process.env.PORT || 3000
app.use(cors())
app.use(bodyParser.json()) // support json encoded bodies
app.use(bodyParser.urlencoded({extended: true})) // support encoded bodies
app.use(express.static("public"))
app.get("*", (req, res, next) => {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((data) => {
const css = new Set()
const context = { data, insertCss: (...styles) => styles.forEach(style => css.add(style._getCss())) }
const markup = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>React on the Server!</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`)
}).catch(next)
})
app.listen(port, () => console.log(`Server is listening on port: ${port}`))
routes.js
import AboutMain from './components/About/AboutMain'
const routes = [
{
path: '/about',
component: AboutMain
}
]
export default routes
browser.js
// Import the neccessary modules for use in file
import React from 'react' // Main React module
import { hydrate } from 'react-dom' // render alternative for server rendering
import App from '../shared/App'
import { BrowserRouter } from 'react-router-dom' // React Router component for client side routing
import '../shared/components/global.scss' // Only has general rules, which do get applied
hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('app')
)
App.js
import React, { Component } from 'react'
import routes from './routes'
import { Route, Link, Redirect, Switch } from 'react-router-dom'
class App extends Component {
render() {
return (
<div>
<Switch>
{routes.map(({ path, exact, component: Component, ...rest }) => (
<Route key={path} path={path} exact={exact} render={(props) => (
<Component {...props} {...rest} />
)} />
))}
<Route render={(props) => <NoMatch {...props} /> } />
</Switch>
</div>
)
}
}
export default App
AboutMain.js
// Importing Required Modules
import React, {Component, Fragment} from 'react' // Importing React, Component, Fragment from "react"
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './about.scss'
class AboutMain extends Component {
state = {
phrase: 'We Made It!'
}
render() {
return (
<Fragment>
<header className={s.banner}>
<h1 className={s.heading}>{this.state.phrase}</h1>
</header>
</Fragment>
)
}
}
export default withStyles(s)(AboutMain) <-- Error Seems to occur here, at least I think.
about.scss
.banner {
margin: 0 auto;
padding: 15px;
border: 2px solid #000;
}
.heading {
text-transform: uppercase;
text-decoration: underline;
}
The problem went away simply because you removed isomorphic-style-loader. Please don't accept your own answer like that. The problem here is you did not provide a context so insertCss.apply(_context, styles) will complain because _context is undefined. To solve the problem, follow these steps:
Create a ContextProvider component in the same directory of App
ContextProvider.js
import React from 'react';
import PropTypes from 'prop-types'
import App from './App'
class ContextProvider extends React.Component {
static childContextTypes = {
insertCss: PropTypes.func,
}
getChildContext() {
return { ...this.props.context }
}
render () {
return <App { ...this.props } />
}
}
export default ContextProvider
Wrap the ContextProvider in BOTH your browser.js and server.js. Remember to declare the context in both files.
browser.js (in other apps, this would be root client code, i.e client.js or index.js)
// Import the neccessary modules for use in file
/* import statements */
const context = {
insertCss: (...styles) => {
const removeCss = styles.map(x => x._insertCss());
return () => {
removeCss.forEach(f => f());
};
},
}
hydrate(
<BrowserRouter>
//ContextProvider wraps around and returns App so we can do this
<ContextProvider context={context} />
</BrowserRouter>,
document.getElementById('app')
)
server.js
//Additional code above
app.get("*", (req, res, next) => {
const activeRoute = routes.find((route) => matchPath(req.url, route)) || {}
const promise = activeRoute.fetchInitialData
? activeRoute.fetchInitialData(req.path)
: Promise.resolve()
promise.then((data) => {
const css = new Set()
const context = { insertCss: (...styles) =>
styles.forEach(style => css.add(style._getCss()))}
const markup = renderToString(
<StaticRouter location={req.url}>
<ContextProvider context={context}>
<App />
</ContextProvider>
</StaticRouter>
)
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>React on the Server!</title>
<script src="/bundle.js" defer></script>
<script>window.__INITIAL_DATA__ = ${serialize(data)}</script>
<style type="text/css">${[...css].join('')}</style>
</head>
<body>
<div id="app">${markup}</div>
</body>
</html>
`)
}).catch(next)
})
app.listen(port, () => console.log(`Server is listening on port: ${port}`))
I wrote an article explaining this in more detail here: https://medium.com/#danielnmai/load-css-in-react-server-side-rendering-with-isomorphic-style-loader-848c8140a096
After reviewing the code all night and endlessly searching Google. I found a fix that the main issue with my code was in the webpack.config.babel.js setup.
I changed the browser test for sass || scss to use style-loader, rather than the isomorphic-style-loader. I also removed all isomorphic-style-loader logic from my app (ie. withStyles, insertCss, etc.)
I'm not sure if this was the correct approach, but for the meantime, it seems to fix my problem and does not return any errors or network issues.

React-hot-loader not re-rending components

I have an application that is serving an EJS view with my React.js bundle loaded in a script tag.
I have followed the instructions for react-hot-loader v3 and #next, neither are working. The are no errors in the console and the components are not being re-rendered on change.
Here is my app entry point:
import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { AppContainer } from 'react-hot-loader'
import { store } from './routes';
import App from './containers/App';
const render = Component => {
ReactDOM.render(
<Provider store={store}>
<MuiThemeProvider>
<AppContainer>
<Component />
</AppContainer>
</MuiThemeProvider>
</Provider>,
document.getElementById('root'))
};
render(App);
//registerServiceWorker();
// Webpack Hot Module Replacement API
if (module.hot) {
console.log('module.hot exists');
module.hot.accept('./containers/App', () => {
console.log('Reloading app');
render(App);
})
}
Here is the App files that the entry point is calling:
import React from 'react';
import Navigation from '../components/Navigation';
import { hot } from 'react-hot-loader'
import createRoutes from '../routes';
const routes = createRoutes();
const App = () => {
return ([
<Navigation key="app-navigation" />,
<main style={{ height: 'calc(100% - 85px)' }} key="app-main">{routes}</main>
])
};
export default hot(module)(App)
Here is my webpack dev config:
const devBrowserRender = {
devtool: 'source-map',
context: PATHS.app,
entry: {
app: ['babel-polyfill', 'react-hot-loader/patch',
'./index']
},
node,
devServer: {
contentBase: PATHS.assets,
hot: true
},
output: {
path: PATHS.assets,
filename: '[name].dev.js',
publicPath: PATHS.public
},
module: { rules: rules({ production: false, browser: true }) },
resolve,
plugins: plugins({ production: false })
};
Here are my JavaScript rules:
const presets = [["es2015", { "modules": false }], 'react', 'stage-0'];
const plugins = production ? [
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
] : [];
return {
test: /\.js$|\.jsx$/,
loader: 'babel-loader',
options: {
presets,
plugins
},
exclude: PATHS.modules
};
Developer plugins:
if (!production) {
return [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin(['NODE_ENV']),
new webpack.DefinePlugin(compileTimeConstantForMinification),
new ExtractTextPlugin({
filename: '[contenthash].css',
allChunks: true
}),
// new webpack.optimize.UglifyJsPlugin({ compress }),
new ManifestPlugin({
fileName: 'manifest.json'
})
];
}
I'm assuming this is coming from a misunderstanding about how react-hot-loader works, but I cannot find any other information about why it wouldn't work in the docs or examples.
I know the pain of configuring this stuff.
You need to include the next lines in your entry section
entry: {
app: [
'react-hot-loader/patch',
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./index.js'
]
}
then when you are setting babel-loader configuration you need to add react-hot-loader/babel
const plugins = production ? [
'transform-react-remove-prop-types',
'transform-react-constant-elements',
'transform-react-inline-elements'
] : ['react-hot-loader/babel'];
Here I have a simple configuration with this feature.
Hope it helps.

Default export works on the development site, but returns undefined in Storybook

So I'm building some component stubs for a new project I'm making. To see the visuals for these components I'm using Storybook. I have two separate webpack configs for the Storybook build and the regular build. Both inherit from a base config, shown below (I've removed some irrelevant loaders to make reading easier):
const path = require('path')
const config = {
output: {
filename: '[name].js',
path: path.join(__dirname, 'public/js')
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react'],
plugins: [
'transform-object-rest-spread',
'transform-es2015-destructuring',
["react-css-modules", {
"filetypes": {
".scss": {
"syntax": "postcss-scss",
"plugins": ["postcss-nested"]
}
},
"generateScopedName": "[local]_[hash:base64:5]"
}]
]
}
}
]
},
resolve: {
modules: ['node_modules', path.join(__dirname, 'resources/assets/js')],
}
}
module.exports = config
My Storybook config and my regular config differ like this:
Webpack.config.js
const path = require('path')
const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const webpackBaseConfig = require(path.join(__dirname, 'webpack.base.config.js'))
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
}),
]
if(process.env.NODE_ENV === 'production') {
plugins.push(new UglifyJSPlugin())
}
const webpackConfig = Object.assign(webpackBaseConfig, {
entry: {
vendor: ['react', 'react-dom', 'react-redux', 'react-router', 'react-router-dom', 'redux-form', 'axios', 'redux'],
app: path.join(__dirname, 'resources/assets/js/app.jsx'),
},
plugins,
})
module.exports = webpackBaseConfig
Webpack.storybook.config.js
const path = require('path')
const webpackBaseConfig = require(path.join(__dirname, '../webpack.base.config.js'))
const storyBookConfig = Object.assign(webpackBaseConfig, {
entry: path.join(__dirname, '../resources/assets/js/app.jsx'),
})
module.exports = storyBookConfig
Now everything works fine when I use the normal build, but when I visit storybook these components seems to break it:
components/AppHeader/AppHeader.component.jsx
import React from 'react'
import { Logo, UserCard } from 'components'
import './AppHeader.scss'
const AppHeader = (props) => {
const { user } = props
return (<div styleName="app-header">
<Logo />
<span styleName="user-profile">
<UserCard firstName={user.firstName} lastName={user.lastName} />
</span>
</div>)
}
export default AppHeader
components/AppHeader/AppHeader.container.jsx
import { connect } from 'react-redux'
import AppHeader from './AppHeader.component.jsx'
const mapStateToProps = (state) => ({
user: state.currentUser,
})
export default connect(
mapStateToProps
)(AppHeader)
The error I get is when exporting the connected component in AppHeader.container.jsx:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in.
So it seems as if the default export in AppHeader.component.jsx is undefined? This is what makes me think that it's a problem with the webpack configuration for Storybook, because the container/component combo works when I view it not in Storybook.
Any suggestions/help would be greatly appreciated, thank you :)

Categories

Resources