Property 'children' is missing in type - javascript

I am trying to setup Storybook with Typescript using babel-loader and ts-loader.
Everything works fine except using children in a React component:
[tsl] ERROR in .../stories/index.stories.tsx(8,56)
TS2769: No overload matches this call.
Property 'children' is missing in type '{ title: string; }' but required in type 'Props'.
This is the .storybook/main.js file:
module.exports = {
addons: [
"#storybook/addon-knobs",
],
stories: ["../packages/**/*.stories.tsx"],
webpackFinal: async config => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('ts-loader')
},
{
loader: require.resolve('babel-loader'),
options: {
presets: [
"#babel/preset-env",
"#babel/preset-react"
]
}
}
],
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}
};
This is the index.stories.tsx file:
import React from "react";
import Collapsible from "../src";
export default {
title: "Collapsible"
};
const content = <span>Content</span>;
export const simpleCollapsible = () => (
<Collapsible title="Collapsible">{content}</Collapsible>
);
And this is the implementation of Collapsible:
import React, { ReactNode, useState } from "react";
import styled, { ThemeProvider } from "styled-components";
import {
BorderProps,
ColorProps,
FlexboxProps,
LayoutProps,
SpaceProps,
TypographyProps
} from "styled-system";
import Theme from "#atw/theme";
import { KeyboardArrowDown } from "#styled-icons/material";
import Box from '~/box';
import Button from '~/button';
interface Props
extends BorderProps,
ColorProps,
FlexboxProps,
LayoutProps,
SpaceProps,
TypographyProps {
children: ReactNode;
title: string;
}
const Collapsible = ({ children, title, ...rest }: Props) => {
const [isCollapsed, setIsCollapsed] = useState(false);
const handleCollapse = () => {
setIsCollapsed(!isCollapsed);
};
return (
<ThemeProvider theme={Theme}>
<Button
border="none"
padding={0}
marginBottom={2}
width={1}
textAlign="start"
onClick={handleCollapse}
{...rest}
>
<IconBox isCollapsed={isCollapsed}>
<KeyboardArrowDown size="24px" />
</IconBox>
{title}
</Button>
{!isCollapsed && (
<Box display="flex" flexDirection="column">
{children}
</Box>
)}
</ThemeProvider>
);
};
export default Collapsible;
Is there anything here I'm doing wrong?

One possible solution is to leverage the default children mechanism in functional components, React.FC, which lets you mount children without explicitly include them as a prop in your type definition. For your case this is achievable by applying the following changes:
interface Props
extends BorderProps,
ColorProps,
FlexboxProps,
LayoutProps,
SpaceProps,
TypographyProps {
title: string;
}
const Collapsible: React.FC<Props> = ({ children, title, ...rest }) => {
...
};
Working sandbox for this

step 1
add React.FC: it already comes with children declared for you. And add your custom Props inside the React's.
Your code should be this:
const Collapsible : React.FC<Props> = ({ children, title, ...rest }) => {
step 2
interface Props extends BorderProps,
ColorProps,
FlexboxProps,
LayoutProps,
SpaceProps,
TypographyProps {
children: ReactNode; // as React.FC declares it for you, just delete this line
title: string;
}

I added the Babel Preset Typescript and the error is gone.
This is what my .storybook/main.js looks like now:
module.exports = {
addons: [
"#storybook/addon-knobs",
],
stories: ["../packages/**/*.stories.tsx"],
webpackFinal: async config => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('ts-loader'),
options: {
configFile: '../tsconfig.json',
transpileOnly: true
}
},
{
loader: require.resolve('babel-loader'),
options: {
presets: [
"#babel/preset-env",
"#babel/preset-react",
"#babel/preset-typescript"
]
}
}
],
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
}
};

Related

React component not rendering correctly after await call

i have html template i purchased at themeforest.net im trying to convert it to webpack and react every thing works fine now but there is weird bug when ever i make await call in componentDidMount the page didnt render correctly
let res = await axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
});
this.setState({ allProducts: res.data });
when i comment the await call
and setstate to static data
let allProducts = [
{
//array data
},
]
this.setState({ allProducts: allProducts });
its render correctly. here is the component
export class MainComponent extends React.Component<{}, any> {
constructor(props) {
super(props);
this.state = {
allProducts: [],
};
}
async componentDidMount() {
let res = await axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
});
this.setState({ allProducts: res.data });
}
render(): any {
return (
<div className="product-4 product-m no-arrow">
{this.state.allProducts.map((x) => (
<div key={x.id} className="product-box product-wrap">
<div className="img-wrapper">
<div className="lable-block">
<span className="lable3">new</span>{" "}
<span className="lable4">on sale</span>
</div>
<div className="front">
<a href={"/product/" + x.id}>
{x.images.map((image) =>
image.main.toString() === "true" ? (
<img
className="img-fluid blur-up lazyload bg-img"
key={image.id}
src={`/public/productImages/${x.id.toString()}/${
image.imageName
}`}
></img>
) : (
""
)
)}
</a>
</div>
</div>
</div>
))}
</div>
// long html lines here
// ...
);
}
}
webpack config
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: path.join(__dirname, "src/index.tsx"),
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.(svg|gif|jpg|png|eot|woff|woff2|ttf)$/,
use: [
'url-loader',
],
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.ts$/,
use: ["ts-loader"],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "index.html"),
filename: "./index.html",
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
}),
],
output: {
path: __dirname + "/dist/",
filename: "index.js",
publicPath: '/'
},
devServer: {
historyApiFallback: true,
proxy: {
"/api": {
target: "http://localhost:5050",
pathRewrite: { "^/api": "" },
},
},
},
mode: "development",
};
entry point index.tsx
import React from "react";
import { render } from "react-dom";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { MainComponent } from "./views/user/main/main";
import { Bottom } from "./views/user/layout/bottom";
import { Top } from "./views/user/layout/top";
import "core-js/stable";
import "regenerator-runtime/runtime";
import "./helpers/css"; //css imports of the html template
render(
<Router>
<Switch>
<Route path="/" exact>
<>
<Top />
<MainComponent />
<Bottom />
</>
</Route>
</Switch>
</Router>,
document.getElementById("r")
);
import "./helpers/js"; //js imports of the html template
and most importantly css and js imports
css.tsx
import "/public/assets/css/fontawesome.css";
import "/public/assets/css/slick.css";
import "/public/assets/css/slick-theme.css";
import "/public/assets/css/animate.css";
import "/public/assets/css/themify-icons.css";
import "/public/assets/css/bootstrap.min.css";
import "/public/assets/css/bootstrap4-toggle.min.css";
import "/public/assets/css/jquery.lazyloadxt.spinner.css";
import "/public/assets/css/color5.css";
import "/public/assets/css/site.css";
js.tsx
import "/public/assets/js/jquery-ui.min.js";
import "/public/assets/js/jquery.exitintent.js";
import "/public/assets/js/exit.js";
// #ts-ignore
window.Popper = require("/public/assets/js/popper.min.js");
import "/public/assets/js/slick.js";
import "/public/assets/js/menu.js";
import "/public/assets/js/lazysizes.min.js";
import "/public/assets/js/bootstrap.min.js";
import "/public/assets/js/bootstrap4-toggle.min.js";
import "/public/assets/js/bootstrap-notify.min.js";
import "/public/assets/js/fly-cart.js";
import "/public/assets/js/script.js";
import "/public/scripts/layout.js";
i suspect its something to do with slick library
ive tried import() slick js and css files after setstate but it doesnt work
this.setState({ allProducts: res.data }, () => {
import("../../../../public/assets/css/slick.css");
import("../../../../public/assets/css/slick-theme.css");
import("../../../../public/assets/js/slick.js");
});
i have also tried re import the whole css and js files but also doesnt work
i have also tried many other things like using ajax instead of axios but it give the exact same bug ive also tried this
axios({
method: "get",
url: "http://localhost:8080/api/main/mainProducts",
}).then((x) => {
this.setState({ allProducts: x.data });
});
no await here but its same bug also.
a picture of when its render correctly
wrong render
any help would be really appreciated.
thanks !

Use custom middleware for async actions. Actions must be plain objects

I am new to this, and this error occurs, looked at a lot of solutions on it, nothing helped to fix.
Another mistake in store.js. When point to thunk.
Argument type ThunkMiddleware & {withExtraArgument (extraArgument: E): ThunkMiddleware{}, AnyAction, E>} is not assignable to parameter type Function
Actions.js
export const SET_YEAR = 'SET_YEAR';
export const FETCH_USERS_EXAMPLE = "FETCH_USERS_EXAMPLE";
export function setYear(year) {
return {
type: 'SET_YEAR',
payload: year,
}
}
export async function getFreeData() {
try {
return async (dispatch) => {
let res = await fetch(`https://jsonplaceholder.typicode.com/users`);
let userList = await res.json();
dispatch({
type: "FETCH_USERS_EXAMPLE",
payload: userList
});
return userList;
}
} catch (e) {
console.log("Error", e);
}
}
Reducer.js
import {SET_YEAR, FETCH_USERS_EXAMPLE} from '../Actions/TestAction';
export function testReducer(state ={year: ''}, action) {
switch (action.type) {
case 'SET_YEAR':
return {...state, year: action.payload};
case 'FETCH_USERS_EXAMPLE':
return {...state, userList: action.payload};
default:
return state
}
}
Container.js
import TestComponent from "./TestComponent";
import {setYear, getFreeData} from "../../Redux/Actions/TestAction";
import {connect} from "react-redux";
import React from "react";
const mapStateToProps = (store) => ({
items: store.user,
userList: store.page.userList,
year: store.page.year
});
const mapDispatchToProps = {
setYear,
getFreeData
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(TestComponent);
Store.js
import {createStore, applyMiddleware} from 'redux'
import {rootReducer} from './Reducers/rootReducer';
import thunk from 'redux-thunk';
import logger from "redux-logger";
export const store = createStore(rootReducer, applyMiddleware(thunk, logger));
webpack
const path = require("path");
module.exports = {
entry: ['babel-polyfill', "./src/index.js"],
mode: "development",
output: {
filename: "./main.js"
},
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 3000,
watchContentBase: true,
progress: true
},
devtool: "source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: ['raw-loader']
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader"
},
{
loader: "sass-loader"
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
}
]
}
};
Your getFreeData function should not be async or it will return a promise.
Instead, return the function for redux-thunk:
export function getFreeData() {
return async (dispatch) => {
try {
let res = await fetch(`https://jsonplaceholder.typicode.com/users`);
let userList = await res.json();
dispatch({
type: "FETCH_USERS_EXAMPLE",
payload: userList
});
return userList;
}
catch (e) {
console.log("Error", e);
}
}
}
Hope this helps.

Storybook + MDX

My .js stories show perfectly on storybook but .mdx stories do not show & I get no error as well
main.js
module.exports = {
addons: [
'#storybook/addon-docs/register',
'#storybook/addon-actions/register',
'#storybook/addon-links/register',
'#storybook/addon-knobs/register',
'#storybook/addon-storysource/register',
'#storybook/addon-viewport/register',
],
};
webpack.config.js
as suggested here https://www.npmjs.com/package/#storybook/addon-docs#manual-configuration
config.module.rules.push({
test: /\.(stories|story)\.mdx?$/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ['#babel/plugin-transform-react-jsx'],
},
},
{
loader: '#mdx-js/loader',
options: {
compilers: [createCompiler({})],
},
},
],
});
config.module.rules.push({
test: /\.(stories|story)\.jsx?$/,
loader: require.resolve('#storybook/source-loader'),
exclude: [/node_modules/],
enforce: 'pre',
});
preview.js
addParameters({
docs: {
container: DocsContainer,
page: DocsPage,
},
});
function loadStories() {
const requires = [require.context('#rrc', true, /\.stories\.(js|mdx)$/)];
for (const req of requires) req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
Now I have 2 types of stories
story.mdx
import { Meta, Story } from '#storybook/addon-docs/blocks';
// Components
import Chips from '../';
<Meta title="AAAAAAAAA AAAAAA/Chip2" component={Chip} />
# Chip
I can define a story with the function imported from CSF:
And I can also embed arbitrary markdown & JSX in this file.
<Chip label="Basic" />
<Preview>
<Story name="all checkboxes">
<form>
<Chip label="Basic" />
</form>
</Story>
</Preview>
### Installing
A step by step series of examples that tell you how to get a development env running
and .js stories which are like
import React from 'react';
import { storiesOf } from '#storybook/react';
import { Chip } from '../../..';
storiesOf('Chip', module)
.addParameters({
component: Chip,
})
.add('Basic', () => <Chip label="Basic" />)
.add('Disabled', () => <Chip label="Disabled" disabled />)

reactjs + webpack + babel 7 Syntax error: The rest element has to be the last element when destructing

I am doing a dev build and I'm getting below babel error. I'm not sure which module/plugin to install for this. Any pointers would be greatly appreciated.
ERROR in ./src/_components/display/DisplayList.jsx
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /src/_components/display/DisplayList.jsx: The rest element has to be the last element when destructing (15:23)
13 | };
14 |
> 15 | const DisplayList = ({ ...props, children }) => {
| ^
16 | const { classes } = props;
17 | console.log(props.data)
18 | return (
Code used in the file /src/_components/display/DisplayList.jsx
import React from 'react';
import PropTypes from 'prop-types';
import { Typography, withStyles, List } from '#material-ui/core';
const listStyle = {
heading: {
textAlign: 'center',
color: '#FFF',
backgroundColor: '#383733',
padding: 10,
marginBottom: 5,
}
};
const DisplayList = ({ ...props, children }) => {
const { classes } = props;
console.log(props.data)
return (
<div>
<Typography className={classes.heading}>
{props.title}
</Typography>
{children &&
children.map((child, key) => {
return (
<React.Fragment key={key}>
{child}
</React.Fragment>
)
})}
</div>
)
}
DisplayList.propTypes = {
title: PropTypes.string.isRequired
}
export default withStyles(listStyle)(DisplayList);
Webpack.config.js file
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
resolve: {
extensions: ['.js', '.jsx'],
},
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
},
],
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
})
]
}
.babelrc file
{
"presets": [
"#babel/env", "#babel/react"
],
"plugins": [
"#babel/proposal-class-properties",
"#babel/transform-react-inline-elements",
"#babel/transform-react-constant-elements",
"#babel/proposal-object-rest-spread",
"#babel/transform-spread"
]
}
I could'nt find much relevant information in the internet that addresses this problem. Any pointers of where I could have gone wrong ?
Is there any babel plugin/module to be installed to get this fixed?
Just like the error message says, move ...props as the last element:
const DisplayList = ({ children, ...props }) => (...)

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.

Categories

Resources