GVKun编程网logo

reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起

14

这篇文章主要围绕reactjs–如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起展开,旨在为您提供一份详细的参考资料。我们将全面介绍reactjs–如何在客户端和服务器

这篇文章主要围绕reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起展开,旨在为您提供一份详细的参考资料。我们将全面介绍reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起,同时也会为您带来node.js – React / Redux同构/服务器端呈现和媒体查询、React Router无法与Webpack Server和Redux一起使用?、react+react-router+react-redux+nodejs+mongodb项目、react+react-router+react-redux全家桶小项目开发过程分享的实用方法。

本文目录一览:

reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起

reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起

我希望我的基于React的SPA能够在服务器端呈现(这些日子不是这样).因此,我想将React与 react-router,redux和一些构建层(如 isomorphic starterkit)结合起来.

有hapi universal redux连在一起,但我正在努力如何组织我的流程.我的数据来自REST API的多个端点.不同的组件具有不同的数据需求,应该及时在客户端上加载数据.在服务器上,必须获取特定路由(组件集)的所有数据,并将必要的组件呈现给字符串.

在我的第一种方法中,我使用redux的中间件来创建异步操作,这些操作加载数据,返回一个promise,并在promise解析时触发SOME_DATA_ARRIVED操作. Reducers然后更新我的商店,组件重新渲染,一切都很好.原则上,这是有效的.但后来我意识到,在路由发挥作用的那一刻,流程变得尴尬.

列出许多数据记录的某个组件具有多个用于过滤记录的链接.每个过滤后的数据集都应该通过它自己的URL提供,例如/ filter-by /:filter.所以我使用不同的< Link to = {...}>用于在单击时更改URL并触发路由器的组件.路由器应根据当前URL表示的状态更新存储,这反过来导致相关组件的重新呈现.

这不容易实现.我首先尝试使用componentwillUpdate来触发一个操作,该操作异步加载我的数据,填充存储并为我的组件引起另一个重新渲染周期.但这不适用于服务器,因为只支持3种生命周期方法.

所以我正在寻找正确的方法来组织这个.用户与应用程序的交互(从用户角度更改应用程序状态)应更新URL. IMO这应该使路由器以某种方式加载必要的数据,更新商店,并开始对帐过程.

所以互动 – >网址更改 – >数据提取 – >商店更新 – >重新渲染.

这种方法也应该在服务器上工作,因为从请求的URL开始,应该能够确定要加载的数据,生成初始状态并将该状态传递给redux的存储生成.但我找不到妥善做到这一点的方法.所以对我来说,出现以下问题:

>我的方法是错误的,因为有些东西我不明白/不知道吗?
>在redux的商店中保持从REST API加载数据是正确的吗?
>在redux商店中保留状态的组件和其他人通过自己管理状态是不是有点尴尬?
>是否有互动的想法 – >网址更改 – >数据提取 – >商店更新 – >重新渲染完全错了?

我愿意接受各种建议.

我今天确实设置了完全相同的东西.我们已经拥有的是react-router和redux.我们模块化了一些模块,将东西注入其中 – 而中提琴 – 它起作用.我用 https://github.com/erikras/react-redux-universal-hot-example作为参考.

部分:

router.js

我们返回一个函数(位置,历史,存储)来使用promises设置路由器. routes是包含所有组件的react-router的路由定义.

module.exports = function (location,history,store) {
    return new Bluebird((resolve,reject)  => {
        Router.run(routes,location,(Handler,state) => {
            const HandlerConnected = connect(_.identity)(Handler);
            const component = (
                <Provider store={store}>
                    {() => <HandlerConnected />}
                </Provider>
            );
            resolve(component);
        }).catch(console.error.bind(console));
    });
};

2. store.js

您只需将初始状态传递给createStore(reducer,initialState).您只需在服务器和客户端上执行此操作.对于客户端,您应该通过脚本标记(即窗口.__ initialstate__)使状态可用.
有关更多信息,请参见http://rackt.github.io/redux/docs/recipes/ServerRendering.html.

3.在服务器上呈现

获取数据,使用该数据设置初始状态(…数据).上面的createRouter = router.js. res.render表示使用以下内容渲染玉石模板

script.
    window.csvistate.__initialstate__=!{initialState ? JSON.stringify(initialState) : 'null'};
...
#react-start
    != html
var initialState = { ...data };
var store = createStore(reducer,initialState);
createRouter(req.url,null,store).then(function (component) {
    var html = React.renderToString(component);
    res.render('community/neighbourhood',{ html: html,initialState: initialState });
});

4.适应客户

然后你的客户可以做同样的事情.位置可以是React-Router的HistoryLocation

const initialState = window.csvistate.__initialstate__;
const store = require('./store')(initialState);

router(location,store).then(component => {
    React.render(component,document.getElementsByClassName('jsx-community-bulletinboard')[0]);
});

回答你的问题:

>你的方法似乎是对的.我们也这样做.人们甚至可以将网址作为州的一部分.> redux商店内的所有州都是好事.这样你就有了一个单一的事实来源.>我们现在还在研究应该去哪里.目前我们在服务器上请求componentDidMount上的数据应该已经存在.

node.js – React / Redux同构/服务器端呈现和媒体查询

node.js – React / Redux同构/服务器端呈现和媒体查询

我开始创建一个基于Node的同构React / Redux应用程序.该项目的一个要求是基于“移动”和“桌面”视图对特定组件进行“自适应”渲染.我已经实现了Redux动作和reducer来存储有关用户视图的屏幕信息(基于媒体查询 – “小”,“中”,“大”).在调整大小时,状态/商店会更新.默认状态为“小”.

const defaultState = {
    isMobile: true,isTablet: false,isDesktop: false,sizes: {
        small: true,medium: false,large: false,huge: false,},};

在需要根据屏幕大小在两个不同版本中呈现“自适应”的组件中,我只需执行以下操作:

if (small) return variation1

if (medium) return variation2

一切正常.

现在我面临两个问题:

>我的应用程序是同构的,这意味着标记也呈现服务器端.服务器对用户的浏览器和媒体查询一无所知.因为我的默认状态是“小”,服务器将始终呈现“variation1”.节点服务器是站点的入口点.看起来渲染需要“延迟”(中间件?),服务器需要在React应用程序“交付”之前从客户端获取有关浏览器宽度的一些信息.知道如何解决这个问题吗?
>因为渲染是基于状态的,所以在加载“变化1”之后总是可以看到几毫秒(闪烁),即使浏览器大小是“桌面”.这是因为在使用当前屏幕宽度更新状态之前,JS检测需要几毫秒.我认为这与上述问题和默认状态一起发挥作用.

我找不到1的任何解决方案,但我想必须有一些同构和响应/自适应的东西.

解决方法

您可以从服务器上的标头获取用户代理,然后使用返回数据的reducer发送带有用户代理信息的redux操作,这样您就可以检测用户是否在手机/平板电脑/桌面/等等上进行相应的渲染

React Router无法与Webpack Server和Redux一起使用?

React Router无法与Webpack Server和Redux一起使用?

当仅使用路径Body组件时,它将在您走的每条路径中呈现,因为对于我在任何路径尝试之前都将Backslash放入的SuccessPageComponent而言,反斜线现在将在每条路径中

 <Switch>
    <Route exact path="/" component={Body} />
    <Route path="/success" component={SuccessPageComponent} />
  </Switch>

一开始我经常使用它,但是如果您看起来需要添加反斜杠,或者转到可以通过以下操作创建的404页面:

<Route component={NoFound} />

像这样您可以创建404页面 react-router-doom doc

react+react-router+react-redux+nodejs+mongodb项目

react+react-router+react-redux+nodejs+mongodb项目

一个实际项目(OA系统)中的部分功能。这个demo中引入了数据库,数据库使用了mongodb。安装mongodb才能运行完整的功能。要看完整的项目可以移步我的github

技术栈

  • React v15.6.2
  • react-redux
  • redux
  • react-router-dom
  • webpack
  • nodeJs
  • mongodb
  • axios

项目结构

```
.
├─ exampleImg/                  # 截图
├─ note/                        # 学习笔记
├─ my-app/                      # 源码目录(开发都在这里进行)
│   ├─ config/                  # 服务配置文件
|   |── controller              # 处理网络请求
│   ├─ model/                   # mongoose Model
│   ├─ route/                   # nodeJs 路由配置
│   ├── schema/                 # mongoose Schema
│   ├── scripts/                # 启动服务的文件
│   ├── src/                    # react代码从这里开始
│   │   ├─ components/          # 全局组件
│   │   ├─ css/                 # 全局css样式
|   |   |── global/             # 全局方法
|   |   |── pages/              # 页面
|   |   |     |── att/          # 考勤分组模块
|   |   |     |── attendance/   # 通讯录模块
|   |   |     |── department/   # 部门管理模块
|   |   |     |── holiday/      # 假期管理
|   |   |     |── member/       # 员工管理
|   |   |── router/             # router
|   |   |── store/              # redux
|   |   |── App.css
|   |   |── App.js
|   |   |── index.css
|   |   |── index.js            # 入口
```

 

项目截图

1.通讯录

2.假期管理

3.考勤分组

4.选择人员

5.员工管理

6.部门管理

 

react+react-router+react-redux全家桶小项目开发过程分享

react+react-router+react-redux全家桶小项目开发过程分享

react-ele-webapp

项目地址 :https://github.com/kliuj/reac...

run

下载完项目

npm install

然后

npm run dev 即可

基于 react react-router redux 的项目,主要是为了学习实战react。数据都是固定的,从饿了么接口临时抓的,模拟了一个0-100ms的异步数据延迟,感谢饿了么。

以下内容是项目开发的过程和一些思考,按照这个过程至少能保证实现一个相对完整的react全家桶项目

内容参考

react文档:http://reactjs.cn/react/docs/...

react-router 文档地址 :https://reacttraining.com/rea...

react-router 中文版参考:http://www.uprogrammer.cn/rea...

redux文档参考:http://redux.js.org/

redux中文文档:http://cn.redux.js.org/

搭建项目:

建立项目目录,安装package.json,配置webpack.config
做好基础依赖工作,摘自package.json的一部分内容

    "devDependencies": {
        "babel-core": "^6.23.1",
        "babel-loader": "^6.4.0",
        "babel-preset-es2015": "^6.22.0",
        "babel-preset-react": "^6.23.0",
        "html-webpack-plugin": "^2.28.0",
        "jshint": "^2.9.4",
        "jshint-loader": "^0.8.4",
        "react": "^15.2.0",
        "react-dom": "^15.2.0",
        "react-router": "^2.0.0",
        "redux": "^3.6.0",
        "webpack": "^2.2.1",
        "webpack-dev-server": "^2.4.1"
    } //JAVASCRIPT

项目模块结构组织一些基础工作

开始进行开发一个项目除了技术选型之外,还有许多基础东西要先设计好,一个好的组织设计要可以为以后的提高工作效率。我这方面还有很多欠缺,目前主要考虑了3个模块的设计:

1:后台接口通信层:model.js 主要处理统一接口的请求发送和回调,放在一起更有利于后期维护,也增加可阅读性

    //接口对应的url,这里只做演示
    const uris = {
          index_entry : fetchData.index_entry,
          hot_search_words : fetchData.hot_search_words
    }
    //接口调用层
    export default function send(url,postData,successCallback,errCallback){
        //模拟延迟,假接口
        let promise = new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(fetchData[url])
            },Math.random()*100)
        })
        promise.then(function(data){
            successCallback(data)
        })
    }

2:本地数据缓存维护:baseStore.js 主要处理页面之间的跳转返回,增加更多的自主性和扩展性

    // 自动存储浏览记录
    export function  saveFrom(prop) {
          let name = prop.pagename,
              transit =  prop.location,
              qhfrom = transit.query.qhfrom ,//默认全部返回首页
              para = transit.query.para ? JSON.parse(transit.query.para) : '''';
          if(!qhfrom) return false;
          let paths  = localStorage.getItem("FromUrlStore") ? JSON.parse(localStorage.getItem("FromUrlStore")) : {};
          if (localStorage) {
            paths[name] = {
              ''name'':qhfrom,//存储来源页面
              ''para'':para //存储来源页面的参数
            }
            localStorage.setItem("FromUrlStore", JSON.stringify(paths));
          }
      }
   //存储页面的来源,统一管理   

3:公共方法的处理:baseFun.js 主要用来定义一些公用的模块方法

    //放置公用函数 
    export function showToast(){
        ...
    }

使用react-router初始化页面

    import React from ''react''
     import { render } from ''react-dom''
     import { Router, Route, Link,hashHistory ,IndexRedirect,IndexRoute} from ''react-router''
     import Home from ''./components/home.jsx''
     import Discover from ''./components/discover.jsx''
     const App = React.createClass({
       render() {
         return (
           <div>
             <footer>
                 <Link to="/home">外卖</Link> 
                 <Link to="/discover?qhfrom=home">发现</Link>
             </footer>
             {this.props.children}
           </div>
         )
       }
     })
     const route = (
          <Router history={hashHistory}>
             <Route path="/" component={App}>
               <IndexRoute component={Home} />
               <Route path="home" component={Home} />
               <Route path="discover" component={Discover} />
             </Route>
           </Router>
     )
     render(route, document.getElementById("app"))

代码简单介绍:
因为没有后台,采用的 hashHistoryhash路由),关于hash路由可以参考:https://github.com/kliuj/spa-... 有简单的介绍。

这个是router的跳转 <Link to="/home">外卖</Link>
这个是加载子路由组件 {this.props.children}
这个是默认的跳转页面 <IndexRoute component={Home} />

处理首页的滚动列表

首页主要分成了4个组件
底部导航 + 滚动列表 + 单个产品 + 首页搜索框

滚动列表封装了一个简单的组件

    <List
        list={Pro}  //每个产品item组件
        pagename={''home''} //跳转产品列表的上级页面  用来处理返回
        data={this.state.productList} //需要渲染的数据
        onScroll = {this.getMore.bind(this)}//滚动加载函数
    />
    在scrollList组件里面监听了滚动事件进行自动加载的处理

react-redux 处理登录和登出

使用redux的原因:用户信息和登录是两个不同的组件,也没有父子级的关系,但是需要进行数据状态共享和相互影响。详细信息可以看上面的官方文档,我这里就简单说一下我这个项目的应用。

定义常量 actionTypes.js

    //登入成功
    export const LOG_SUCCESS = ''LOG_SUCCESS''
    //正在登录
    export const LOG_ING = ''LOG_ING''
    //注销登录
    export const LOG_OUT = ''LOG_OUT''
    //主要是统一保存状态对应的名称

定义具体的触发操作 actions/login.js

    //注销 同步
    export function log_out (){
        return {
            type:actionTypes.LOG_OUT
        }
    }
    //登入 异步
    export function log_in (obj){
        return dispatch=>{
            //pending  正在进行登录的状态
            dispatch({type:actionTypes.LOG_ING})
            //开始发送异步请求登录
            new Promise((resolve,reject)=>{
                ...
            }).then(res=>{
                dispatch(res)
            })
        }
    }
    //异步状态需要使用中间件

处理数据 reducers/login.js

    export default function(state = initialData,action){
        switch(action.type){
            case actionTypes.LOG_SUCCESS:
                return {
                    loginstate:1,
                    username:action.username
                }
                break
            case actionTypes.LOG_ING:
                return{
                    loginstate:-1,
                    username:''正在登录''
                }   
            case actionTypes.LOG_OUT:
                return initialData
                break
            default :
                return initialData  
        }
    }

使用中间件创建store层 store/store.js

    import {createStore, applyMiddleware} from ''redux''
    import thunk from ''redux-thunk''
    //合并的多个reducer,解耦
    import rootReducer from ''../reducers/index.js''
    const middlewares = [thunk]
    const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore)
    export default function configureStore(initialState){
        return createStoreWithMiddleware(rootReducer,initialState)
    }

在路由层引入

    import {Provider} from ''react-redux''
    const store = configureStore()
    const route = (
      <Provider store={store}>
          <Router history={hashHistory}>
              ...
          </Router>
      </Provider>
    )

组件里面使用

    import { connect } from ''react-redux''
    import {log_out} from ''../../actions/login.js'' //操作
    ...
    ...
    function mapStateToProps(userinfo){
        let {login} = userinfo //这个是返回的所有reducer,我们只用当前需要的,参考 reducers/index.js 内容
        return login
    }
    export default connect(mapStateToProps)(UserInfo)
    //这个时候就可以在当前组件状态的  this.props 获取到这个 login 数据,
    //操作的时候  
    const {dispatch} = this.props;
    dispatch(log_out())
    //这时候就可以操作redux状态的数据,每次数据改变都会下发给所有接收的组件

以上,我们就使用了许多东西完成了一个简单的小项目

关于reactjs – 如何在客户端和服务器端呈现逻辑上将react-router和redux组合在一起的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于node.js – React / Redux同构/服务器端呈现和媒体查询、React Router无法与Webpack Server和Redux一起使用?、react+react-router+react-redux+nodejs+mongodb项目、react+react-router+react-redux全家桶小项目开发过程分享等相关知识的信息别忘了在本站进行查找喔。

本文标签: