如何使用Redux + Immutable js进行服务器端渲染?

时间:2017-06-28 14:03:33

标签: javascript node.js reactjs redux immutable.js

我想在我的应用程序中使用不可变的js。但它有点难以进行服务器端呈现它会引发我这样的错误

  

TypeError:state.allPosts.toJS不是函数

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)

客户端/ 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')
        })

    })


});

更新

如下所述,我搜索并最终以此结束。

The preloadedState argument passed to createStore has unexpected type of "String". Expected argument to be an object with the following keys: "allPosts", "routing

这是我的更新代码

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);
    });

}

0 个答案:

没有答案