资讯专栏INFORMATION COLUMN

从无到有-在create-react-app基础上接入react-router、redux-saga

褰辩话 / 562人阅读

摘要:将所有的需要鉴权的页面放在例如下,只有在有微信相关鉴权的信息存在,才允许访问接下来的界面,否则,容器内甚至可以直接不渲染接下来的界面。而接下来的则是把路由导向至了一个微信端专用的。

搭建项目框架 新建项目

执行如下代码,用create-react-app来建立项目的基础框架,然后安装需要用到的依赖。

$ npx create-react-app my-test-project
$ cd my-test-project
$ yarn add react-router-dom react-redux prop-types redux redux-saga
$ yarn start

完成后,应用启动在localhost的3000端口。

接入react-router-dom

react-router-dom其实就是react-router 4.0,与之前的3.0有什么区别呢?react-router被一分为三。react-routerreact-router-domreact-router-native

react-router实现了路由的核心的路由组件和函数。而react-router-domreact-router-native则是基于react-router,提供了特定的环境的组件。

react-router-dom依赖react-router,安装的时候,不用再显示的安装react-router, 如果你有机会去看react-router-dom的源码,就会发现里面有些组件都是从react-router中引入的。

新建layout

/src下新建layout目录。为什么要新建layout目录,因为有可能我们会用到多个layout,layout是一个什么样的概念?

例如这个应用需要提供一部分功能在微信使用。那么进入所有微信的相关界面下都要进行鉴权。没有鉴权信息就不允许访问,但是这个服务仍然有所有人都可以访问的路由。使用layout可以很好的帮我们解决这个问题。

将所有的需要鉴权的页面放在例如WechatContainer下,只有在有微信相关鉴权的信息存在,才允许访问接下来的界面,否则,容器内甚至可以直接不渲染接下来的界面。

/src/layout下新建两个文件,分别是AppLayout.jsWechatLayout.js

AppLayout.js的代码如下。在这个layout中,首页就是单纯的一个路由,导向至首页。而接下来的/wechat则是把路由导向至了一个微信端专用的layout。

import React, { Component } from "react";
import Home from "../routes/home";
import WechatLayout from "./WechatLayout";
import { Route, Switch } from "react-router-dom";

/**
 * 项目入口布局
 * 在此处根据一级路由的不同进入不同的container
 * 每个container有自己不同的作用
 *
 * 在react-router V4中,将原先统一在一处的路由分散到各个模块中,分散到各个模块当中
 * 例如: WechatLayout的路由为/wechat 表示到该layout下的默认路径
 */
class AppLayout extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  render() {
    return (
      
); } } export default AppLayout;

WechatLayout.js的代码如下。在这个layout中,我们就可以对访问该路由的用户进行鉴权。如果没有权限,我们可以直接限制用户的访问,甚至直接不渲染render中的数据。

例如,我们可以在componentWillMount中或者在render中,根据当前的state数据,对当前用户进行鉴权。如果没有权限,我们就可以将当前页面重定向到没有权限的提示界面。

import React, { Component } from "react";
import Home from "../routes/wechat/home";
import { Route, Switch } from "react-router-dom";
import { connect } from "react-redux";

class WechatLayout extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  componentWillMount() {
  }

  render() {
    const className = "Wechat-Layout";

    return (
      
Our Manage Layout
); } } const mapStateToProps = state => ({ reducer: state.wechatLayout }); export default connect(mapStateToProps)(WechatLayout);
新建routes

新建/src/routes/home/index.js,代码如下。

import React, { Component } from "react";
import {Link} from "react-router-dom";

class Home extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  render() {
    const className = "Home";

    return (
      

This is Home

Manage Home
); } } export default Home;

新建/src/routes/wechat/home/index.js, 代码如下。在代码中可以看到,触发reducer很简单,只需要调用dispatch方法即可。dispatch中的payload就是该请求所带的参数,该参数会传到saga中间层,去调用真正的后端请求。并在请求返回成功之后,调用put方法更新state。

import React, { Component } from "react";
import {connect} from "react-redux";

class Home extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  componentWillMount() {
    this.props.dispatch({ type: "WATCH_GET_PROJECT", payload: { projectName: "tap4fun" } });
  }

  render() {
    const className = "Wechat-Home";

    return (
      

Home

The project name is : { this.props.reducer.projectName }

); } } const mapStateToProps = state => ({ reducer: state.wechat }); export default connect(mapStateToProps)(Home)
新建container

/src下新建container,在container中新建文件AppContainer.js。我们整个react应用都装在这个容器里面。AppContainer.js的代码如下。

而其中的Provider组件,将包裹我们应用的容器AppLayout包在其中,使得下面的所有子组件都可以拿到state。Provider接受store参数作为props,然后通过context往下传递。

import React, { Component } from "react";
import PropTypes from "prop-types";
import { Provider } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
import AppLayout from "../layout/AppLayout";

class AppContainer extends Component {
  constructor(props) {
    super(props);

    this.state = {};
  }

  static propTypes = {
    store: PropTypes.object.isRequired
  };

  render() {
    const { store } = this.props;

    return (
      
        
          
        
      
    );
  }
}

export default AppContainer;
修改项目入口文件

更新/src/index.js,代码如下。在此处会将create出来的store容器当作属性传入到Appcontainer中,作为我们应用的状态容器。

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import * as serviceWorker from "./serviceWorker";
import AppContainer from "./container/AppContainer";
import createStore from "./store/createStore";

const store = createStore();

ReactDOM.render(, document.getElementById("root"));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
新建store

新建/src/store/craeteStore.js,代码如下。通过以下的方式,我们可以给redux添加很多中间件,甚至是自己写的中间件。

比如,我们可以自己实现一个日志中间件,然后添加到中间件数组middleWares中,在创建redux的store的时候,应用我们自己写的中间件。

import { applyMiddleware, compose, createStore } from "redux";
import createSagaMiddleware  from "redux-saga";
import rootReducer from "../reducers";
import rootSaga  from "../saga";

export default function configureStore(preloadedState) {
  // 创建saga中间件
  const sagaMiddleware = createSagaMiddleware();
  const middleWares = [sagaMiddleware];
  const middlewareEnhancer = applyMiddleware(...middleWares);

  const enhancers = [middlewareEnhancer];
  const composedEnhancers = compose(...enhancers);

  // 创建存储容器
  const store = createStore(rootReducer, preloadedState, composedEnhancers);
  sagaMiddleware.run(rootSaga);

  return store;
}

在这引入了redux-saga。我之前在使用redux的时候,几乎在每个模块都要写相应的action和reducer,然后在相应的模块文件中引入action的函数,然后在使用mapDispatchToProps将该函数注入到props中,在相应的函数中调用。并且,一个action不能复用,即使触发的是相同的reducer。这样就会出现很多重复性的代码,新增一个模块的工作也相对繁琐了很多。

但是使用了redux-saga之后,只需要在reducer中定义好相应类型的操作和saga就可以了。不需要定义action的函数,不需要在文件中引入action中函数,甚至连mapDispatchToProps都不需要,直接使用this.props.dispatch({ "type": "WATCH_GET_PROJECT" })就可以调用。而且,action可以复用。

新建saga

新建/src/saga/index.js,代码如下。

import { put, takeEvery } from "redux-saga/effects";
import { delay } from "redux-saga";

export function* fetchProject() {
  yield delay(1000);
  yield put({ type: "GET_PROJECT" })
}

export default function * rootSaga() {
  yield takeEvery("WATCH_GET_PROJECT", fetchProject);
}
新建reducer

新建/src/reducers/wechat.js,代码如下。

const initialState = {
  projectName: null
};

export default function counter(state = initialState, action) {
  let newState = state;
  switch (action.type) {
    case "GET_PROJECT":
      newState.projectName = action.payload.projectName;
      break;
    default:
      break;
  }
  return {...newState}
}

新建/src/reducers/index.js,代码如下。

import { combineReducers } from "redux";
import Wechat from "./wechat";

export default combineReducers({
  wechat: Wechat
});

在这里我们使用了combineReducers。在之前的基于redux的应用程序中,常见的state结构就是一个简单的JavaScript对象。

重新启动应用

到此处,重新启动应用,就可以在http://localhost:3000/wechat/home下看到从reducer中取出的数据。

在页面中,我们就可以通过代码this.props.dispatch的方式,来触发action。

参考

https://github.com/mrdulin/bl...

https://cn.redux.js.org/docs/...

项目源代码

Github仓库

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100102.html

相关文章

  • 分享一个react单页应用脚手架

    摘要:项目技术栈项目地址项目演示现在比较流行的脚手架应该是,由官方开发。网上关于项目的目录结构也很多,那应该怎么合理地去组织我们的目录结构呢为了处理这个问题,我参考了一些项目,然后把它们的优点结合起来,最后写了这个脚手架。 项目技术栈:react16+react-router4+antd-mobile2+mobx+axios+webpack4项目github地址:https://github...

    kycool 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    bergwhite 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    txgcwm 评论0 收藏0
  • React生态,dva源码阅读

    摘要:下面会从浅到深,淡淡在阅读源码过程中自己的理解。分拆子页面后,每一个子页面对应一个文件。总结上面就是最早版本的源码,很简洁的使用了等其目的也很简单简化相关生态的繁琐逻辑参考源码地址   dva的思想还是很不错的,大大提升了开发效率,dva集成了Redux以及Redux的中间件Redux-saga,以及React-router等等。得益于Redux的状态管理,以及Redux-saga中...

    harryhappy 评论0 收藏0
  • React 328道最全面试题(持续更新)

    摘要:希望大家在这浮夸的前端圈里,保持冷静,坚持每天花分钟来学习与思考。 今天的React题没有太多的故事…… 半个月前出了248个Vue的知识点,受到很多朋友的关注,都强烈要求再出多些React相前的面试题,受到大家的邀请,我又找了20多个React的使用者,他们给出了328道React的面试题,由我整理好发给大家,同时发布在了前端面试每日3+1的React专题,希望对大家有所帮助,同时大...

    kumfo 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<