问题
I would like to Use Immutable js with my App .But It's Kinda difficult for server side rendering It throws me a error like this
TypeError: state.allPosts.toJS is not a function
Home.js
import React,{Component} from 'react';
import {Helmet} from 'react-helmet';
import {connect} from 'react-redux';
import * as allPosts from '../Redux/Actions/AllPosts_action'
class Home extends Component{
renderAllPosts(){
const {posts} = this.props;
return(
posts.postArr.map(({id,title,body}) => {
return <li key={id}>{title}</li>
})
)
}
render(){
return(
<div>
<Helmet>
<meta charSet="utf-8" />
<title>My Title</title>
<link rel="stylesheet" type="text/css" href="/static/css/Home.css" />
</Helmet>
{this.renderAllPosts()}
</div>
)
}
}
Home.fetchData = ({store,location, params, history}) => store.dispatch(allPosts.getAllPosts());
const mapStateToProps = (state) => {
return{
posts:state.allPosts.toJS() //This throws the error
}
};
const mapDispatchToProps = (dispatch) => {
return {
getAllPosts:() => dispatch(allPosts.getAllPosts())
}
};
export default connect(mapStateToProps,mapDispatchToProps)(Home)
Client/Index.js
import React,{Component} from 'react';
import {render} from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import configureStore from './Redux/Store/configureStore';
import {Provider} from 'react-redux';
import MainRoutes from './MainRouter';
import {fromJS} from 'immutable';
//window.__STATE__ this is my server rendered state But it not in the immutable form
const store = configureStore(window.__STATE__);
console.log(store.getState())
const RenderApp = (Component) => {
render(
<AppContainer>
<Provider store={store}>
<Component store={store}/>
</Provider>
</AppContainer>,
document.getElementById('app')
)
};
RenderApp(MainRoutes);
if (module.hot) {
module.hot.accept('./MainRouter', () => {
const nextMainRoutes = require('./MainRouter');
RenderApp(nextMainRoutes);
});
}
Server.js
app.get('*',(req,res,next) => {
// res.sendFile(path.join(__dirname,'./index.html'));
match({routes:routes(),location:req.url},(err,redirectLocation,renderProps) => {
// Err Handling
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search)
}
if (!renderProps) {
return next(new Error('Missing render props'))
}
const components = renderProps.components;
const Comp = components[components.length - 1].WrappedComponent;
const fetchData = (Comp && Comp.fetchData) || (() => Promise.resolve())
const initialState = {}
const store = createStore(reducer, initialState, applyMiddleware(thunk));
const { location, params, history } = renderProps
fetchData({store,location,params,history}).then(() => {
const body = renderToStaticMarkup(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
)
const state = store.getState();
let head = Helmet.rewind();
res.send(`<!DOCTYPE html>
<html>
<head>
${head.title}
${head.meta}
${head.link}
</head>
<body>
<div id="app" >${body}</div>
<script>window.__STATE__=${JSON.stringify(state)}</script>
<script src="/static/vendor.js"></script>
<script src="/static/app.js"></script>
</body>
</html>`)
}).catch(err => {
console.log(err,'From Store Fetch')
})
})
});
UPDATE
As commented below I searched and finally end up like this .
The preloadedState argument passed to createStore has unexpected type of "String". Expected argument to be an object with the following keys: "allPosts", "routing
This is my Updated Code
import React,{Component} from 'react';
import {render} from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import configureStore from './Redux/Store/configureStore';
import {Provider} from 'react-redux';
import MainRoutes from './MainRouter';
function toJS(js) {
for (let el in js) {
if (!isPlainObj(js[el]) && !Array.isArray(js[el]))
js[el] = js[el].toJS()
}
return js
}
function isPlainObj(value) {
return value && (value.constructor === Object || value.constructor === undefined);
}
const initialState = JSON.stringify(toJS(window.__STATE__))
const store = configureStore(initialState);
console.log(store.getState())
const RenderApp = (Component) => {
render(
<AppContainer>
<Provider store={store}>
<Component store={store}/>
</Provider>
</AppContainer>,
document.getElementById('app')
)
};
RenderApp(MainRoutes);
if (module.hot) {
module.hot.accept('./MainRouter', () => {
const nextMainRoutes = require('./MainRouter');
RenderApp(nextMainRoutes);
});
}
来源:https://stackoverflow.com/questions/44804769/how-to-do-server-side-rendering-with-redux-immutable-js