Reputation: 41
I'm trying to load a static HTML from the meteor server side that also uses redux and router. However, every time I try to render my component with renderToString() I get the error indicated in the title. What am I doing wrong?
I've already tried using React.renderComponentToString as a possible alternative, but I get the error that React.renderComponentToString is not a function. How else am I going to pass an argument?
import React from 'react';
import {onPageLoad} from 'meteor/server-render';
import {StaticRouter} from 'react-router';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import {Helmet} from 'react-helmet';
import rootReducer, {initialState} from '../redux/reducers';
import HomePage from '../ui/homepage/HomePage';
export default renderServerPage = onPageLoad(sink => {
const context = {};
const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
const MyApp = props => {
return (
<Provider store={store}>
<StaticRouter location={sink.request.url} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
// The following line is causing the error
sink.renderIntoElementById('app', renderToString(<MyApp />));
const helmet = Helmet.renderStatic();
sink.appendToHead(helmet.title.toString(
"Afterschools, Enrichment Programs, Growth, & Experiences - Fun2Bright"
));
sink.appendToBody(
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script>
);
});
My other attempts include the following: 1) creating a component outside of the scope within the same file and passing store and sink.request.url as props
function MyApp (props) {
const context = {};
return (
<Provider store={props.store}>
<StaticRouter location={props.location} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
2) basically creating the same component but in another file and importing the component.
3) directly putting the element inside the renderToString:
sink.renderIntoElementById('app', renderToString(
<Provider store={store}>
<StaticRouter location={sink.request.url} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
));
4) using React.createElement without passing any props:
sink.renderIntoElementById('app', renderToString(React.createElement(MyApp)));
5) commenting out the following just to see if it's caused by any of my other imported components
<Route path="/" component={HomePage}/>
Upvotes: 1
Views: 80
Reputation: 41
I finally figured the issue. It turns out that simply using react-router
doesn't allow me to use DOM-aware components like and , so I needed to use react-router-dom
instead. react-router-dom also re-exports all of react-router's exports, so I'll only ever need to use react-router-dom
. I changed everything to be imported from 'react-router-dom':
import {Route, StaticRouter} from 'react-router-dom';
...
// inside onPageLoad
const App = props => {
return (
<Provider store={store}>
<StaticRouter location={props.location} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
sink.renderIntoElementById('app', renderToString(<App store={store} location={sink.request.url}/>));
I found this from here: https://github.com/ReactTraining/react-router/issues/4648
Upvotes: 1