Redux进级类别3,一步一步学习
分类:前端技术

在 2017 年求学 React Redux 的一些建议(中篇)

2017/09/11 · JavaScript · React, Redux

初稿出处: 郭永峰   

本文起头解析f8app大旨js部分的源码,那篇文章将卓殊难了然,原因了Redux框架引进了超多新定义,使用了一大波函数式编制程序思想,提议先把后边的参照小说留心过三回,确认保证领悟后再看本文。React Native的观点是Learn once,write anywhere, Android和iOS App端的js代码是身处一块儿的,以便最大限度的复用业务逻辑,UI部分的能够依赖平台湾特务色各自实现,React native分别渲染成安卓和iOS的原生UI分界面,对于三个平台UI组件的细微差距和完全两样的UI组件2种状态,react native提供了不相同的管理方式。

写在开始

上篇中,完结了 TODO 列表展示, TODO 项状态改良,增添新 TODO。
只是选取的 React Native 情势调控 state,这里,大家初叶利用 Redux 调节 state,也就是 React Native Redux 开发。

源码:https://github.com/eylu/web-lib/tree/master/ReactReduxDemo/app_step1

Redux升级类别小说:

1. React Redux品种构造最棒推行
2. 怎么客观地布署State

在近日两篇文章中,大家介绍了Redux项目结构的团协会措施和如何布置State。本篇,我们将以往边两篇小说为底子,继续介绍怎样设计action、reducer、selector。

照例以博客项目为例,大家在第2篇中最后设计的state构造如下:

{
  "app":{
    "isFetching": false,
    "error": "",
  },
  "posts":{
    "byId": {
      "1": {
        ...
      },
      ...
    },
    "allIds": [1, ...],
  } 
  "comments": {
    ...
  },
  "authors": {
    ...
  }
}

依附那些组织,大家十分轻易想到能够拆分成4个reducer分别管理app、posts、comments、authors这4个子state。子state相关的action和这些state对应的reducer放到二个文本中,作为八个state管理模块。介怀:本文定义的action、reducer、selector并不分包真实博客应用中提到的兼具逻辑,仅列举部分逻辑,用以介绍如何设计action、reducer、selector。

state中的 app 管理使用状态,应用状态与世界情形不一样,领域情形是选取用来突显、操作的数额,日常供给从服务器端获取,比方posts、comments、authors都归于世界情形;而利用状态是与使用行为或应用UI直接相关的意况,比方当前利用中是不是正在开展互连网央求,应用实践时的错误新闻等。app 包涵的施用状态有:isFetching(当前接收中是还是不是正在进行互连网诉求卡塔尔和error(应用实施时的错误音信卡塔尔国。对应的action能够定义为:

// 所在文件:app.js
//action types
export const types = {
  const START_FETCH  : 'app/START_FETCH',
  const FINISH_FETCH : 'app/FINISH_FETCH',
  const SET_ERROR : 'app/SET_ERROR'
}

//action creators
export const actions = {
  startFetch: () => {
    return {type: types.START_FETCH};
  },
  finishFetch: ()=> {
    return {type: types.FINISH_FETCH};
  },
  setError: (error)=> {
    return {type: types.SET_ERROR, payload: error};
  }
}

types定义了app模块使用的action types,每贰个action type的值以模块名作为命名空间,防止止分裂模块的action type冲突难点。actions定义了该模块使用到的action creators。大家并未有向来导出每二个action type和action creator,而是把具有的action type封装到types常量,全体的action creators封装到actions常量,再导出types和actions那多少个常量。那样做的功利是便于在别的模块中援引。(在第1篇中早就介绍过卡塔尔(قطر‎
近日再来定义管理app的reducer:

// 所在文件:app.js

export const types = {
 //...
}

export const actions = {
 //...
}

const initialState = {
  isFetching: false,
  error: null,
}

// reducer
export default function reducer(state = initialState, action) {
  switch (action.type) {
    types.START_FETCH: 
      return {...state, isFetching: true};
    types.FINISH_FETCH:
      return {...state, isFetching: false};
    types.SET_ERROR:
      return {...state, error: action.payload}
    default: return state;
  }
}

现今,app.js就结成了贰当中坚的管理state的模块。

大家再来看下怎么着计划posts.js。posts是这多少个子状态中最复杂的场所,包括了posts领域数据的三种集体育赛工作办公室法:byId定义了博客ID和博客的绚烂关系,allIds定义了博客在界面上的来得顺序。那一个模块需要使用异步action调用服务器端API,获取博客数据。当网络央浼初步和了结时,还亟需选用app.js模块中的actions,用来校订app中的isFetching状态。代码如下所示:

// 所在文件:posts.js
import {actions as appActions} from './app.js'

//action types
export const types = {
  const SET_POSTS : 'posts/SET_POSTS',
}

//action creators
export const actions = {
  // 异步action,需要redux-thunk支持
  getPosts: () => {
    return (dispatch) => {
      dispatch(appActions.startFetch());
      return fetch('http://xxx/posts')
        .then(response => response.json())
        .then(json => {
          dispatch(actions.setPosts(json));    
          dispatch(appActions.finishFetch());    
        });      
    }
  },
  setPosts: (posts)=> {
    return {type: types.SET_POSTS, payload: posts};
  }
}

// reducer
export default function reducer(state = [], action) {
  switch (action.type) {
    types.SET_POSTS:
      let byId = {};
      let allIds = [];
      /* 假设接口返回的博客数据格式为:
      [{
        "id": 1,
        "title": "Blog Title",
        "create_time": "2017-01-10T23:07:43.248Z",
        "author": {
          "id": 81,
          "name": "Mr Shelby"
        },
        "comments": [{id: 'c1', authorId: 81, content: 'Say something'}]
        "content": "Some really short blog content. "
      }] 
      */
      action.payload.each((item)=>{
        byId[item.id] = item;
        allIds.push(item.id);
      })
      return {...state, byId, allIds};
    default: return state;
  }
}

我们在一个reducer函数中管理了byId和allIds三个意况,当posts的事务逻辑较轻便,需求管理的action也很少时,如下边包车型客车例证所示,这么做是没反常的。但当posts的政工逻辑比较复杂,action类型相当多,byId和allIds响应的action也不生龙活虎致时,往往我们会拆分出三个reducer,分别管理byId和allIds。如下所示:

// 所在文件:posts.js
import { combineReducers } from 'redux'

//省略无关代码

// reducer
export default combineReducers({
  byId,
  allIds
})

const byId = (state = {}, action) {
  switch (action.type) {
    types.SET_POSTS:
      let byId = {};
      action.payload.each((item)=>{
        byId[item.id] = item;
      })
      return {...state, byId};
    SOME_SEPCIAL_ACTION_FOR_BYID:
      //...
    default: return state;
  }
}

const allIds = (state = [], action) {
  switch (action.type) {
    types.SET_POSTS:
      return {...state, allIds: action.payload.map(item => item.id)};
    SOME_SEPCIAL_ACTION_FOR_ALLIDS:
      //...
    default: return state;
  }
}

从上面的例子中,大家得以窥见,redux的combineReducers能够在自由层级的state上运用,而毫无只好在率先级的state上行使(示例中的第生机勃勃层级state是app、posts、comments、authors卡塔尔国

posts.js模块还应该有一个主题素材,便是byId中的种种post对象,包蕴嵌套对象author。大家应当让post对象只行使博客作者的id就能够:

// reducer
export default function reducer(state = [], action) {
  switch (action.type) {
    types.SET_POSTS:
      let byId = {};
      let allIds = [];
      action.payload.each((item)=>{
        byId[item.id] = {...item, author: item.author.id};
        allIds.push(item.id);
      })
      return {...state, byId, allIds};
    default: return state;
  }
}

如此那般,posts只关乎博客作者的id,博客笔者的别的属性由特地的小圈子状态author来治本:

// 所在文件:authors.js
import { types as postTypes } from './post'

//action types
export const types = {

}

//action creators
export const actions = {

}

// reducer
export default function reducer(state = {}, action){
  switch (action.type) {
    postTypes.SET_POSTS:
      let authors = {};
      action.payload.each((item)=>{
        authors[item.author.id] = item.author;
      })
      return authors;
    default: return state;
}

这里须要当心的是,authors的reducer也管理了posts模块中的SET_POSTS这几个action type。那是不曾经担当何难题的,贰个action本身正是能够被多个state的reducer管理的,极度是当四个state之间存在关联关系时,这种处境更是宽泛。

comments.js模块的达成思路相符,不再赘述。现在我们的redux(放置redux模块)目录布局如下:

redux/
  app.js
  posts.js 
  authors.js
  comments.js

在redux目录层级下,大家新建一个index.js文件,用于把各类模块的reducer合并成最后的根reducer。

// 文件名:index.js
import { combineReducers } from 'redux';
import app from './app';
import posts from './posts';
import authors from './authors';
import commments from './comments';

const rootReducer = combineReducers({
  app,
  posts,
  authors,
  commments
});

export default rootReducer;

action和reducer的宏图到此基本到位,上边大家来看selector。Redux中,selector的“名誉”不及action、reducer洪亮,但selector其实非常常有效。selector是用来从state中获得所需数据的函数,经常在connect的首先个参数 mapStateToProps中央银行使。比方,大家在AuthorContainer.js中依据小编id获取作者详细的情况新闻,不选用selector的话,能够如此写:

//文件名:AuthorContainer.js

//省略无关代码

function mapStateToProps(state, props) {
  return {
    author: state.authors[props.authorId],
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AuthorContainer);

以此例子中,因为逻辑很简短,直接拿到author看起来没什么难题,但当拿到状态的逻辑变得复杂时,需求通过三个函数来拿到,这些函数便是叁个selector。selector是足以复用的,分裂的器皿组件,只要得到状态的逻辑肖似,就足以复用相通的selector。所以,selector不能直接定义在有些容器组件中,而应该定义在其涉及领域所在的模块中,这些例子须求定义在authors.js中。

//authors.js

//action types

//action creators

// reducer

// selectors
export function getAuthorById(state, id) {
  return state[id]
}

在AuthorContainer.js中使用selector:

//文件名:AuthorContainer.js
import { getAuthorById } from '../redux/authors';

//省略无关代码

function mapStateToProps(state, props) {
  return {
    author: getAuthorById(state.authors, props.authorId),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AuthorContainer);

作者们再来看贰个繁缛些的selector:获取生机勃勃篇博客的评论和介绍列表。获取探讨列表数据,要求posts和comments多个世界的数额,所以那么些selector并不切合放置comments.js模块中。当叁个selector的思考参数重视八个状态时,能够把那么些selector放到index.js中,大家把index.js看做全人体模型块层级之上的三个根模块。

// index.js

// 省略无关代码

// selectors
export function getCommentsByPost(post, comments) {
  const commentIds = post.comments;
  return commentIds.map(id => comments[id]);
}

小编们在第2篇 如何合理地安顿Redux的State讲过,要像安排数据库相通设计state,selector就约等于查询表的sql语句,reducer约等于改良表的sql语句。所以,本篇的总计是:像写sql相似,设计和社团action、reducer、selector。


接待关切自己的众生号:老干的大前端,领取21本大前端精选书籍!

图片 1

image

图片 2对于学习 Redux 的局地指出

React 和 Redux 平日结合在联合签字利用,Redux 是 flux 结构方式的风度翩翩种名牌产品特产产品新品优品精致充完毕,况且在 React 社区被周围选拔,但亦不是全然和 React 耦合在后生可畏道的。

js入口分析

React Native Android App和iOS App的入口jsbundle对应的暗中认可js源文件分别是index.android.js和index.ios.js,在f8app中那2个公文内容相似。代码如下:

'use strict';

const {AppRegistry} = require('react-native');
const setup = require('./js/setup');

AppRegistry.registerComponent('F8v2', setup);

React Native采取了组件化编制程序的思辨,在React Native项目中,全体体现的分界面,都足以视作是八个零器件(Component)。
index.android.js利用Node.js的require机制引进setup包,然后注册到AppRegistry.

Redux 简介

Redux 三宝: Store 、Action 、Reducer。

全局 state

并非全体的大局state都急需被寄放起来,一些组件能够选取 setState 来治本组件的内部原因,那也是为什么在攻读 Redux 前要精通 React 中的 setState ,不然你将习于旧贯式的把全数的global state都存款和储蓄在store里面。所以思虑一下,在巨型开垦协会内部开荒的眼花缭乱应用,你更无法将运用的富有 state 都切换到全局状态。

js目录布局拆解解析

先是依然先看下js目录的布局:

├── F8App.js
├── F8Navigator.js
├── FacebookSDK.js
├── Playground.js
├── PushNotificationsController.js
├── actions
│   ├── config.js
│   ├── filter.js
│   ├── index.js
│   ├── installation.js
│   ├── login.js
│   ├── navigation.js
│   ├── notifications.js
│   ├── parse.js
│   ├── schedule.js
│   ├── surveys.js
│   ├── test.js
│   └── types.js
├── common
│   ├── BackButtonIcon.js
│   ├── Carousel.js
│   ├── F8Button.js
│   ├── F8Colors.js
│   ├── F8DrawerLayout.js
│   ├── F8Header.js
│   ├── F8PageControl.js
│   ├── F8SegmentedControl.js
│   ├── F8StyleSheet.js
│   ├── F8Text.js
│   ├── F8Touchable.js
│   ├── ItemsWithSeparator.js
│   ├── ListContainer.js
│   ├── LoginButton.js
│   ├── MapView.js
│   ├── ParallaxBackground.js
│   ├── ProfilePicture.js
│   ├── PureListView.js
│   ├── ViewPager.js
│   └── img
├── env.js
├── filter
│   ├── FilterScreen.js
│   ├── FriendsList.js
│   ├── Header.js
│   ├── Section.js
│   └── TopicItem.js
├── flow-lib.js
├── login
│   ├── LoginModal.js
│   ├── LoginScreen.js
│   └── img
├── rating
│   ├── Header.js
│   ├── RatingCard.js
│   ├── RatingQuestion.js
│   ├── RatingScreen.js
│   └── img
├── reducers
│   ├── __mocks__
│   │   └── parse.js
│   ├── __tests__
│   │   ├── maps-test.js
│   │   ├── notifications-test.js
│   │   └── schedule-test.js
│   ├── config.js
│   ├── createParseReducer.js
│   ├── filter.js
│   ├── friendsSchedules.js
│   ├── index.js
│   ├── maps.js
│   ├── navigation.js
│   ├── notifications.js
│   ├── schedule.js
│   ├── sessions.js
│   ├── surveys.js
│   ├── topics.js
│   └── user.js
├── setup.js
├── store
│   ├── analytics.js
│   ├── array.js
│   ├── configureStore.js
│   ├── promise.js
│   └── track.js
└── tabs
    ├── F8TabsView.android.js
    ├── F8TabsView.ios.js
    ├── MenuItem.js
    ├── img
    ├── info
    │   ├── CommonQuestions.js
    │   ├── F8InfoView.js
    │   ├── LinksList.js
    │   ├── Section.js
    │   ├── ThirdPartyNotices.js
    │   ├── WiFiDetails.js
    │   └── img
    ├── maps
    │   ├── F8MapView.js
    │   ├── ZoomableImage.js
    │   └── img
    ├── notifications
    │   ├── F8NotificationsView.js
    │   ├── NotificationCell.js
    │   ├── PushNUXModal.js
    │   ├── RateSessionsCell.js
    │   ├── allNotifications.js
    │   ├── findSessionByURI.js
    │   ├── img
    │   └── unseenNotificationsCount.js
    └── schedule
        ├── AddToScheduleButton.js
        ├── EmptySchedule.js
        ├── F8FriendGoing.js
        ├── F8SessionCell.js
        ├── F8SessionDetails.js
        ├── F8SpeakerProfile.js
        ├── FilterHeader.js
        ├── FriendCell.js
        ├── FriendsListView.js
        ├── FriendsScheduleView.js
        ├── FriendsUsingApp.js
        ├── GeneralScheduleView.js
        ├── InviteFriendsButton.js
        ├── MyScheduleView.js
        ├── ProfileButton.js
        ├── ScheduleListView.js
        ├── SessionsCarousel.js
        ├── SessionsSectionHeader.js
        ├── SharingSettingsCommon.js
        ├── SharingSettingsModal.js
        ├── SharingSettingsScreen.js
        ├── __tests__
        │   ├── formatDuration-test.js
        │   └── formatTime-test.js
        ├── filterSessions.js
        ├── formatDuration.js
        ├── formatTime.js
        ├── groupSessions.js
        └── img

js部分的代码掌握起来依旧相比较艰巨的,首先要掌握javascript ES6,React Native和Redux的广大语法,还供给弄驾驭redux-react,redux-promise,redux-thunk等插件的功力和原理,不然直接看代码会非常不方便,主要涉嫌的新定义比较多,语法比较奇异。

Redux - 构造上深受 flux 启迪,完结上却更挨近于 elm,只怕说更赞成于函数式编制程序的贰个数据层完成。和 flux 结构对数据层的描述最大的区分就在于 Redux 是接收不可变单风度翩翩状态树来管理应用程序数据的。用 redux 充作数据层也得以完全相配 flux 布局(但没好处)並且 redux 对视图层也向来不趋势性,只是近日用的比很多的或者react。redux使用了不菲函数式编程的概念,举个例子柯里化等的。

  • actions目录下的js实现了业务层的逻辑。
  • common目录下是抽出的有的UI组件,react是依靠组件化编制程序的。
  • filter目录下是有个别UI组件页面,暂前卫未想清楚怎么叫filter
  • login目录下是登入页面,提供了经过推文(Tweet卡塔尔(英语:State of Qatar)帐号登陆F8app的功效
  • rating目录下是投票和问卷相关的页面
  • reduces目录是redux Reducer相关的文件。Redux有且只有四个State状态树,为了制止那么些情况树变得特别复杂,Redux通过 Reducers来担当管理整个应用的State树,而Reducers可以被分成三个个Reducer。
  • store目录下是redux store相关的公文
  • tabs目录下是App 4个tab页面包车型客车源文件
    全方位目录构造划分依然相比客观的。

Action: 所做操作的描述

其本质上是三个 JavaScript 对象,包含四个必需的字段 type ,以致别的数据项。相通于如此 { type: 'ACTION_NAME', attr1: 'data1', attr2: 'data2' } 。然则,大家会选用函数 ActionCreator(args) 来创建 Action 。

诸如:增加 TODO 项,大家会使用上面的函数来成立 Action,带有 TODO 项的称谓。并且,大家会把 Action 的 type 字段用常量赋值,不直接运用字符串,以便更加好的管制与援引。

const ADD_TODO = 'ADD_TODO';

function addTodo(text){
    return {type: ADD_TODO, text}
}

种类目录怎么着组织

这篇文章organizing-redux-application 给出了二种建议措施来企业项目布局。

先是种方法是按效果与利益划分

React Redux 的有个别科目日常给大家体现按效果与利益划分的目录,这也是大器晚成种很好的 React Redux 学习方式,不过,将选用的享有 reducers 和 actions 都坐落于特意的文书夹维护的方案,实际不是全部人都能支持。

JavaScript

src/ --actions/ --reducers/ --components/

1
2
3
4
src/
--actions/
--reducers/
--components/

不经常听到的有建设性的主张是,目录划分应该以组件为主题,各个目录应当有组件本身以致它所对应的 reducers、actions,那么一个示范的目录布局应当是那般的:

JavaScript

message/ --components --reducer.js --actions.js

1
2
3
4
message/
--components
--reducer.js
--actions.js

叁个包涵 container component 、presenter component以致测量检验相关的事无巨细的机件目录会是那样的:

JavaScript

message/ --components/ ----messageItem/ ------presenter.js ------spec.js ----messageList/ ------container.js ------presenter.js ------spec.js --reducer/ ----index.js ----spec.js --actions/ ----index.js ----spec.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
message/
--components/
----messageItem/
------presenter.js
------spec.js
----messageList/
------container.js
------presenter.js
------spec.js
--reducer/
----index.js
----spec.js
--actions/
----index.js
----spec.js

本来了,也并非膏腴贵游都会赏识这种艺术。(其实,作者个人是超级赞成那样的左右维护组件的尺度的,因为将逐风姿罗曼蒂克功效性的reducer和action都丢到相应的目录,那之后维护起来会越加不便,文件也不佳找,那可不疑似MVC那样的分层构造。)极其是将reducer蒙蔽在相继职能目录中,那也不便于全局性的来精通使用 redux 的布局意图。所以提出是适当的量的在中期就抽取一些 reducers 来分享他们所包含的功效。

但在具体景况中,特别是多少个组织在同三个选用类型中合营的时候,在开采进度的压力之下,并从未那么多机遇来科学的悬空出部分 reducers。反而普通是一口气的包装全部的功效模块,只为了以为把活给干完了,让急需准时上线。

第两种情势是对成效模块划分清楚的界限

给各样模块都安装贰个 index.js 文件作为入口,那一个文件只是用于导出一些API给别的的模块使用。在依附 React

  • Redux 的应用中,index.js 文件能够用来导出一个 container components ,或是一个presenter components、action creators、能用来别的地点的 reducer(但不是最后的reducer)。那么,基于那样的思辨,我们的目录就足以改为这样了:

JavaScript

message/ --index.js --components/ ----messageItem/ ------index.js ------presenter.js ------spec.js ----messageList/ ------index.js ------container.js ------presenter.js ------spec.js --reducer/ ----index.js ----spec.js --actions/ ----index.js ----spec.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
message/
--index.js
--components/
----messageItem/
------index.js
------presenter.js
------spec.js
----messageList/
------index.js
------container.js
------presenter.js
------spec.js
--reducer/
----index.js
----spec.js
--actions/
----index.js
----spec.js

那就是说,在时下功用模块下的 index.js 文件应该包蕴那些代码:

JavaScript

import MessageList from './messageList'; export default MessageList; export MessageItem from './messageItem'; export reducer from './reducer'; export actions from './actions';

1
2
3
4
5
6
7
import MessageList from './messageList';
 
export default MessageList;
 
export MessageItem from './messageItem';
export reducer from './reducer';
export actions from './actions';

好了,那样表面包车型客车别样模块就能够这么在她的 index.js 文件中调用 message 模块了。

JavaScript

// bad import { reducer } from ./message/reducer; // good import { reducer } from ./message;

1
2
3
4
5
// bad
import { reducer } from ./message/reducer;
 
// good
import { reducer } from ./message;

收获:按作用模块以及清楚的数不完可以援救大家很好的组织代码和目录。

理解Redux

redux

上边是乐乎上对Redux的二个相比较好的解释,弄掌握了Redux大家才有力量深入分析f8app js的代码。

了解 React,但不知晓 Redux,该如何简单明了的知道 Redux?
解答这几个主题素材并不困难:唯生机勃勃的渴求是您熟识React。
不要光听外人描述名词,精晓起来是十分不便的。
从需要出发,看看使用React须要怎么样:

  1. React有props和state: props意味着父级分发下来的习性,state意味着组件内部能够自行保管的意况,而且整个React未有数量向上回溯的技艺,也正是说数据只可以单向向下分发,可能机关内部消食。
    了解那些是领会React和Redux的前提。
  2. 诚如构建的React组件内部恐怕是叁个完璧归赵的使用,它和睦办事能够,你能够经过品质作为API调节它。可是更加多的时候开采React根本无法让多个零件相互调换,使用对方的数目。
    接下来当时不通过DOM交换(也便是React体制内)解决的有一无二方法正是升级state,将state放到共有的父组件中来管理,再作为props分发回子组件。
  3. 子组件改造父组件state的措施只好是经过onClick触发父组件评释好的回调,约等于父组件提前证明好函数或格局作为左券描述本人的state将怎么样变化,再将它相近作为质量交给子组件使用。
    如此这般就现身了多个格局:数据连接单向从顶层向下分发的,然则唯有子组件回调在概念上得以重返state顶层影响多少。那样state一定水准上是响应式的。
  4. 为了面前碰着全体希望的扩展难题,最轻巧想到的办法正是把富有state聚焦停放全部组件顶层,然后分发给持有组件。
  5. 为了有更加好的state管理,就要求三个库来作为更规范的顶层state分发给持有React应用,那正是Redux。让咱们回到拜见再度现身上边布局的须求:
    a. 供给回调公告state (等同于回调参数卡塔尔(英语:State of Qatar) -> action
    b. 须要依赖回调解和管理理 (等同于父级方法卡塔尔国 -> reducer
    c. 要求state (等同于总状态卡塔尔国 -> store
    对Redux来讲独有这多少个要素:
    a. action是纯阐明式的数据结构,只提供事件的有所因素,不提供逻辑。
    b. reducer是多少个匹配函数,action的殡葬是大局的:全数的reducer都足以捕捉到并合营与协和辅车相依与否,相关就拿走action中的要素举办逻辑管理,修正store中的状态,不相干就不对state做管理原样重回。
    c. store担任存款和储蓄状态并得以被react api回调,公布action.
    当然平日不会直接把三个库拿来用,还恐怕有二个binding叫react-redux, 提供三个Provider和connect。很几个人实际上看懂了redux卡在这里间。
    a. Provider是三个平时组件,能够看作顶层app的分发点,它只须求store属性就足以了。它会将state分发给具有被connect的组件,不管它在何地,被嵌套多少层。
    b. connect是当真的根本,它是三个Corey化函数,意思是先采纳三个参数(数据绑定mapStateToProps和事件绑定mapDispatchToProps),再选择三个参数(将在绑定的组件本人):
    mapStateToProps:营造好Redux系统的时候,它会被自动开头化,可是你的React组件并不知道它的留存,因而你必要分拣出你须求的Redux状态,所以您必要绑定三个函数,它的参数是state,轻便重回您爱戴的多少个值。
    mapDispatchToProps:证明好的action作为回调,也能够被注入到零器件里,正是经过那几个函数,它的参数是dispatch,通过redux的帮扶方法bindActionCreator绑定全部action以至参数的dispatch,就足以看成品质在组件里面作为函数轻巧利用了,不需求手动dispatch。那个mapDispatchToProps是可选的,若是不传那些参数redux会简单把dispatch作为质量注入给组件,能够手动当做store.dispatch使用。那也是怎么要Corey化的原因。
    做好以上流程Redux和React就足以干活了。轻便地说便是:
    1.顶层散发状态,让React组件被动地渲染。
    2.监听事件,事件有职责回到全体情况顶层影响事态。

和 Flux 相似,Redux 让使用的意况变化变得愈加可预测。假诺您想改换使用的事态,就亟须 dispatch 叁个 action。你从未主意直接改换使用的状态,因为保存这几个意况的东西(称为 store)独有 getter 而还未 setter。对于 Flux 和 Redux 来讲,这么些概念都以相仿的。

那么为啥要新布署大器晚成种结构呢?Redux 的创立者 Dan Abramov 发掘了改良 Flux 布局的或是。他想要三个越来越好的开垦者工具来调度 Flux 应用。他开掘只要有一些对 Flux 结构实香港行政局部调节,就足以支付出意气风发款更好用的开荒者工具,同一时间还是能够享受 Flux 构造带来你的可预测性。

Redux富含了代码热替换(hot reload)和时间游览(time travel)功效。

Reducer: 状态 state 更新函数

它是一个纯函数,选择三个参数:stateaction,再次回到三个新的 state

(state, action) => state

留意:谨记 reducer 必须求保持单纯。
假诺传入参数相近,重回总结得到的下一个 state 就决然相似。没有异样情形、未有副功效,未有 API 央浼、未有变量修改,单纯实践计算。

举例:

const ADD_TODO = 'ADD_TODO';

function myReducers(state=[], action){
    switch(action.type){            
        case ADD_TODO:
            return [
                ...state,
                {
                    title: action.text,
                    status: false,
                }
            ]
        default:
            return state;
    }
}

调用:
// 这里是 Action (ActionCreator)
function addTodo(text){
    return {type:ADD_TODO, text}
}
// 这里是 State
let state = [{title: '吃早饭',status:true},{title: '打电话',status:false}];
let newState = myReducers(state, addTodo('看电视'));  
// newState =>  [{title: '吃早饭', status: true},{title: '打电话', status: false}, {title: '看电视', status: false} ];

事实上行使中,大家并不会那样使用 reducer ,这里只是展现三个回到结果。
实际,大家会这么使用 reducer
1、创建 store ,将 reducer 作为参数字传送入
2、使用 store 派发(dispatch) 操作(action)
3、store 内部奉行 reducer

取名约定

在软件编程中命名可正是生龙活虎件令人脑仁疼的政工,那跟给男女命名相近费力,哈哈。合适的命名是落到实处可维护性、易于精晓的代码的最棒实践,React

  • Redux 的行使中提供了大气的自律来提携大家公司代码,何况不会在命名上刚愎自用。无论你的函数封装在 reducer 依旧 component 中,在action creator 或是 selector 中,你都应有有多少个命名约束,並且在扩充应用早先就规定怎么着命名,不然日常会让大家陷入波谲云诡的回调养重构个中。

而自身习于旧贯为各类项目标函数都增添贰个前缀。

  • 在组件的callback中,为种种函数都助长 on 作为前缀,比方 onCreateTiggoplay
  • 在更换 state 的 reducer 中加上 applay 作为前缀,举个例子applyCreateReply
  • 在 selector 中 加上 get 作为前缀,譬如 getReply
  • 在 action creator 中增加 do 作为前缀,譬喻 doCreateReply

唯恐你不自然习贯这种增进前缀的章程,然则笔者要么引进给您,同有时间也建议找到自个儿钟爱的命名约束准则。

智能组件(smart components)和木偶组件(dumb components卡塔尔

Flux 具有调控型视图(controller views) 和常规型视图(regular views)。调控型视图就如叁个老总相同,管理着 store 和子视图(child views)之间的通讯。

在 Redux 中,也会有三个像样的定义:智能组件和木偶组件。(注:在最新的 Redux 文书档案中,它们分小名称叫容器型组件 Container component 和呈现型组件 Presentational component)智能组件的天职就如首席推行官同样,可是比起 Flux 中的剧中人物,Redux 对经营的职责有了更加多的概念:

  • 智能组件负担全数的 action 相关的办事。借使智能组件里带有的四个玩偶组件需求接触一个action,智能组件会由此 props 传二个 function 给木偶组件,而木偶组件能够在必要触发 action 时调用这几个 function。
  • 智能组件不定义 CSS 样式。
  • 智能组件差相当少不会时有发生自身的 DOM 节点,他的行事是团体若干的木偶组件,由木偶组件来扭转最终的 DOM 节点。

Store: 状态 state 容器

它不仅是 state 容器,更是将 reduceraction 连接到了一起。
Store 有以下职责:

  • 保持应用的 state;
  • 提供 getState(卡塔尔国 方法获得 state;
  • 提供 dispatch(action卡塔尔(英语:State of Qatar) 方法创新 state;
  • 透过 subscribe(listener卡塔尔 注册监听器;
  • 经过 subscribe(listener卡塔尔国 再次回到的函数注销监听器。

谨记:
Redux 应用唯有二个十足的 store。当要求拆分数据管理逻辑时,你应该使用 reducer 组合实际不是创立多个 store。

创建 Store

store 的创设非常不难,使用 redux 提供的 createStore() ,并传播八个参数,reducer 和 state
reducer : 随着应用的扩大,reducer 也变得复杂,我们须求将其拆分成小的 reducer ,并运用 combineReducers() 归并成一个 reducer 。
state : 初阶状态,可选。

利用示例:

import { createStore, combineReducers } from 'redux';

function reducers(state, action){ ... }

function actionCreator(args){ ... }

let store = createStore(reducers)  // 或者
let store = createStore(reducers, {key1:'data1'})

store.getState() 
store.dispatch(actionCreator)

// 使用 combineReducers 创建 Store
function reducer1(state, action){ ... }
function reducer2(state, action){ ... }
let combine = combineReducers({
    reducer1,
    reducer2
});
let store = createStore(combine)

追踪状态的转移

在相连迭代中的应用免不了定义多量的 action,何况还需求追溯 state 是何等转移的,redux-logger 能够扶植你看到有着的 state change。每条日志都会显得出 previous state、奉行的 action、next state。

唯独你得保险 actions 是可被装置的,因此小编建议为不一样连串的 action 都增多一个前缀,举个例子那样:

JavaScript

const MESSAGE_CREATE_REPLY = 'message/CREATE_REPLY';

1
const MESSAGE_CREATE_REPLY = 'message/CREATE_REPLY';

那样的话,无论你在哪天触发了新闻过来这么些动作,你都能见到 message/CREATE_REPLY 这一条日志,要是现身 state 卓殊,便能相当慢查到是那条错误的 state 改造而引致的。

redux-thunk 介绍

先贴官方网站链接:https://github.com/gaearon/redux-thunk
Thunk的做法便是扩展了那么些action creator。
Redux官方网址说,action正是Plain JavaScript Object。Thunk允许action creator重临一个函数,何况那个函数第3个参数是dispatch。
A thunk is a function that wraps an expression to delay its evaluation.

// calculation of 1   2 is immediate
// x === 3
let x = 1   2;

// calculation of 1   2 is delayed
// foo can be called later to perform the calculation
// foo is a thunk!
let foo = () => 1   2;

Redux 使用的三尺度

1、Single source of truth
纯净数据源。整个应用的state,存款和储蓄在唯意气风发二个object中,同不时候也唯有三个store用于存款和储蓄这么些object.
2、State is read-only
事态是只读的。唯一能改造state的方式,正是触发action操作。action是用来陈述正在产生的风浪的一个对象。
3、Changes are made with pure functions
在改造state tree时,用到action,同偶然候也急需编写制定对应的reducers才干落成state改造操作。

不遗余力让 state tree 扁平化

Redux 中,扁平化的 state tree能够令你的 reducers 更加的简短,那样你就没有供给在全部 store 的境况树中深层的物色到有些state 后再将其校勘,而是能够很自在的就能够促成。不过,在 Redux 中却不能够做如此做,因为 state 是不可变的。

风流倜傥旦你正在开采多个博客应用,须要保险一个像样那样的列表对象,列表中含有 authorcomment 字段:

JavaScript

{ post: { author: {}, comments: [], } }

1
2
3
4
5
6
{
  post: {
    author: {},
    comments: [],
  }
}

不过事实上境况是各类对象都急需有相应的 id 来开展敬性格很顽强在艰难险阻或巨大压力面前不屈:

JavaScript

{ post: { id: '1', author: { id: 'a', ... }, comments: [ { id: 'z', ... }, ... ], } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  post: {
    id: '1',
    author: {
      id: 'a',
      ...
    },
    comments: [
      {
        id: 'z',
        ...
      },
      ...
    ],
  }
}

本条时候,我们将数据体系化之后将会变得更有意义,数据解构变得进一步扁平化了。体系化之后的多寡通过 id 关联别的字段,之后,你就能够透过实体对象来将其薪资,通过 id 来进行关联数据的研究。

JavaScript

{ posts: { 1: { authorId: 'a', commentIds: ['z', ...] } }, authors: { a: { ... } }, comments: { z: { ... } }, }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
  posts: {
    1: {
      authorId: 'a',
      commentIds: ['z', ...]
    }
  },
  authors: {
    a: {
      ...
    }
  },
  comments: {
    z: {
      ...
    }
  },
}

这么,数据布局看起来就不在那么深层嵌套了,当你须求转移多少的时候,就足以轻易的贯彻数量的不可变性了。

normalizr 是个有力的 library,能够扶助我们开展数量格式化,噢耶~!

setup.js代码深入分析

深谙React Native都精通,index.android.js和index.ios.js分别是Android和iOS App的js程序入口,当然实际运营是减掉管理后的jsbundle。这几个2个公文都以挂号了setup组件,AppRegistry.registerComponent('F8v2', setup);
setup.js担当安顿其余的零件,具体代码如下:

//js/setup.js

var F8App = require('F8App');
var FacebookSDK = require('FacebookSDK');
var Parse = require('parse/react-native');
var React = require('React');
var Relay = require('react-relay');

var { Provider } = require('react-redux');
var configureStore = require('./store/configureStore');

var {serverURL} = require('./env');

function setup(): React.Component {
  console.disableYellowBox = true;
  Parse.initialize('oss-f8-app-2016');
  Parse.serverURL = `${serverURL}/parse`;

  FacebookSDK.init();
  Parse.FacebookUtils.init();
  Relay.injectNetworkLayer(
    new Relay.DefaultNetworkLayer(`${serverURL}/graphql`, {
      fetchTimeout: 30000,
      retryDelays: [5000, 10000],
    })
  );

  class Root extends React.Component {
    constructor() {
      super();
      this.state = {
        isLoading: true,
        store: configureStore(() => this.setState({isLoading: false})),
      };
    }
    render() {
      if (this.state.isLoading) {
        return null;
      }
      return (
        <Provider store={this.state.store}>
          <F8App />
        </Provider>
      );
    }
  }

  return Root;
}

global.LOG = (...args) => {
  console.log('/------------------------------\');
  console.log(...args);
  console.log('\------------------------------/');
  return args[args.length - 1];
};

module.exports = setup;

setup.js负担对总体app举办构造,首先配置了Parse,推特SDK和Relay,那3个零零件是劳务器端相关的。
接下来通过react-redux配置了Provider组件,那些组件封装在全方位组件树的最外层。这么些组件让根组件的装有子孙组件能够轻巧的选拔connect(卡塔尔 方法绑定 store。Provider 本质上成立了一个用于更新视图组件的互联网。这个智能组件通过 connect(卡塔尔(قطر‎方法连入那几个互联网,以此保险他们力所能及收获到状态的换代。
configureStore提供了对Store的开创和配备,由于Redux唯有一个store,要是让store 完全部独用立处理自身的事,store会变的很复杂。因而,Redux 中的 store 首先会保留整个应用的全体情形,然后将「推断哪部分动静必要退换」的职务分配下去。而以根 reducer(root reducer)为首的 reducer 们将会负担这么些职责。

// ./js/store/configureStore.js

'use strict';

var {applyMiddleware, createStore} = require('redux');
var thunk = require('redux-thunk');
var promise = require('./promise');
var array = require('./array');
var analytics = require('./analytics');
var reducers = require('../reducers');
var createLogger = require('redux-logger');
var {persistStore, autoRehydrate} = require('redux-persist');
var {AsyncStorage} = require('react-native');

var isDebuggingInChrome = __DEV__ && !!window.navigator.userAgent;

var logger = createLogger({
  predicate: (getState, action) => isDebuggingInChrome,
  collapsed: true,
  duration: true,
});

var createF8Store = applyMiddleware(thunk, promise, array, analytics, logger)(createStore);

function configureStore(onComplete: ?() => void) {
  // TODO(frantic): reconsider usage of redux-persist, maybe add cache breaker
  const store = autoRehydrate()(createF8Store)(reducers);
  persistStore(store, {storage: AsyncStorage}, onComplete);
  if (isDebuggingInChrome) {
    window.store = store;
  }
  return store;
}

module.exports = configureStore;

createF8Store使用了柯里化方法调用了applyMiddleware,middleware咱俩能够大约的通晓成过滤器,效率便是参加一些中级管理进度。最终回到store对象。

React 与 Redux 配合

实际,Redux 并非 React 的直属,不确定与 React 合作使用。它能够与 React、Angular、Ember、jQuery 以致纯 JavaScript 等同盟利用。
但是,像 React 这种 state => UI 类型的框架与之合作,使用起来照旧很爽的!!

单纯数据源原则

格式化之后的数额足以援助您按一块的不二诀要来管理 state ,而生龙活虎旦伏乞后端接口后回到的是深层嵌套的 blogposts 数据构造呢,是否欲哭无泪啊?! post 字段依旧带有 authorcomments字段,可是此番,comments 是叁个数组,数组中的各类对象都有 author 字段:

JavaScript

{ post: { author: { id: 'a' }, comments: [ { author: { id: 'b' }, reply: {}, }, { author: { id: 'a' }, reply: {}, }, ], } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  post: {
    author: { id: 'a' },
    comments: [
      {
        author: { id: 'b' },
        reply: {},
      },
      {
        author: { id: 'a' },
        reply: {},
      },
    ],
  }
}

咱俩能够见见数据布局中 author 字段在 postcomments 中都有维护,那就诱致嵌套的数据布局中现身了若干次,那就不是十足数据源,当您转移了author 字段的时候就能够变得很困难了。

以那个时候候当您将数据格式化之后, author 那个字段就唯有一个了。

JavaScript

{ authors: { a: {}, b: {}, } }

1
2
3
4
5
6
{
  authors: {
    a: {},
    b: {},
  }
}

当你想 follow 一个 author 的时候,就足以轻巧的翻新一个字段了 — 数据源是纯粹的:

JavaScript

{ authors: { a: { isFollowed: true }, b: {}, } }

1
2
3
4
5
6
{
  authors: {
    a: { isFollowed: true },
    b: {},
  }
}

运用中存有信任了 author 那么些字段的地点都能收获更新。

客户登陆流程代码解析

下边解析登入页面包车型地铁代码,代码在login目录下,包含LoginModal.js和LoginScreen.js,达成了通过Oauth登陆推特帐号的固守。
签到涉及的代码有actions/types.js(定义了有着的Action事件卡塔尔(قطر‎, actions/login.js(完成登陆职业逻辑,与服务器交互),js/reducers/user.js(完结对客商相关情状的计量卡塔尔(英语:State of Qatar)。
签到的输入是js/tabs/schedule/logIn.js,142行定义了<LoginButton source="My F8" /> ,LoginButton组件封装了登陆UI相关的逻辑。
点击LoginButton后会调用logIn函数,logIn函数会调用logInWith推特(Twitter卡塔尔(TWTQashqai.US卡塔尔(قطر‎实行OAuth登入或在等待15s后超时再次来到,下边是logIn的代码:

async logIn() {
  const {dispatch, onLoggedIn} = this.props;

  this.setState({isLoading: true});
  try {
    await Promise.race([
      dispatch(logInWithFacebook(this.props.source)),
      timeout(15000),
    ]);
  } catch (e) {
    const message = e.message || e;
    if (message !== 'Timed out' && message !== 'Canceled by user') {
      alert(message);
      console.warn(e);
    }
    return;
  } finally {
    this._isMounted && this.setState({isLoading: false});
  }

  onLoggedIn && onLoggedIn();
}
}

用到了async,Promise.race等ES6的语法。
logInWithInstagram的落实在js/actions/login.js中,假如登陆成功会由此Promise异步获取老铁的日程和查明问卷。

function logInWithFacebook(source: ?string): ThunkAction {
  return (dispatch) => {
    const login = _logInWithFacebook(source);

    // Loading friends schedules shouldn't block the login process
    login.then(
      (result) => {
        dispatch(result);
        dispatch(loadFriendsSchedules());
        dispatch(loadSurveys());
      }
    );
    return login;
  };
}

登入是调用Instagram(TWTTiguan.US卡塔尔SDK进行登入,logInWith推特是个异步方法,用到了ES6的async,
async function _logInWithFacebook(source: ?string): Promise<Array<Action>> {...}
再次回到值是个Promise,在then方面里面异步调用loadFriendsSchedules,loadSurveys。
那个方法会继续呼吁数据,并更新store,进而让页面更新。

react-redux

我们得以接收 react-redux 那些工具把 React 与 Redux 联系起来。它提供多个职能: ProviderConnect
Provider : 一个 Component ,用来包裹应用程序的根组件(入口组件卡塔尔国,提供 store 属性,以供子组件使用。使用方法雷同于那样:

let store = createStore(()=>{});
<Provider store={store}>
       <HomeContainer />
</Provider> 

Connect : 见名知意,将包装好的组件连接到Redux。尽量只做二个顶层的组件,可能route 管理。从本领上来讲你可以将采用中的任何叁个零件 connect(卡塔尔国 到 Redux store 中,但尽量制止这么做,因为那些数据流很难追踪。使用办法形似于如此:

export default connect()(HomeContainer)  // 它将我们的容器组件 `HomeContainer` 连接到 Redux。

Selectors

您还未有动用 selectors 吗?不妨,在 redux 中还是能够通过 mapStateToProps 来计算 props

JavaScript

function mapStateToProps(state) { return { isShown: state.list.length > 0, }; };

1
2
3
4
5
function mapStateToProps(state) {
  return {
    isShown: state.list.length > 0,
  };
};

而什么你只要接收了 selectors 之后的话,你就能够将这有的乘除的劳作嵌入 selectors,从而让 mapStateToProps 更加的简要:

JavaScript

function mapStateToProps(state) { return { isShown: getIsShown(state), }; };

1
2
3
4
5
function mapStateToProps(state) {
  return {
    isShown: getIsShown(state),
  };
};

你能够选取 reselect 来扶植您完了那些专门的学问,它可以扶助你从 state 中总结拿到衍生的多寡,並且让你的行使的性情获得提高:

  • Selectors 可以推导出衍生数据,并传递所需数据的最小集,不用三回把具有数据都给组件,消除品质难点
  • Selectors是可构成的,它能够当作任何 Selectors 的输入
  • Reselect所提供的 selector 是特别飞快,除非它的参数改换了,不然 selector 不会再也总括,那在纷纭应用中对品质提高是极其有利于的。

总结

js部分的代码用了累累ES6的新语法和函数式编制程序思想,极其是使用了Redux框架,代码量也正如大,深入分析和精晓起来相比艰巨,本文只深入分析了部分金榜题名模块的代码。极度是在相关的手艺和框架领悟程度相当不足深切,缺乏实际付出经验的状态下(那说的正是本人自个儿啊)。提议看代码从前先把JavaScript ES6和Redux框架敏而好学一下。尽管代码看上去很难,但总体管理流程和模块划分依然很显然的。

明亮数据流

这里是 react 数据流

图片 3

react 数据流.png

这里是 react redux 数据流

图片 4

react redux 数据流.png

不再多说,上代码!!!

绵绵的重构

随着年华得推移,你会想要重构你的代码,无论是你在运用中运用了 React 、React Redux 只怕此外前端框架,你总会到处的左右更高效的代码协会格局,也许是某个很好的设计情势。

假定您的运用中的组件比很多,你能够找到一个越来越好的形式来分别和团体木偶组件和容器组件,你会发掘他们中间的关联并做一些共用的收取;倘使你还不曾利用非常的命名节制,你也得以在重构的时候去做那几个事情。

参照他事他说加以考察随笔

  • Redux 华语文书档案
  • 《看漫画,学 Redux》 —— A cartoon intro to Redux
  • redux源码安详严整
  • 运用Redux管理你的React应用
  • 知情 React,但不清楚 Redux,该怎么老妪能解的接头 Redux
  • 学习 redux.js 的 流水账

React Redux 开发

Generators, Sagas, Observables, Epics, …

Redux 是二个非常非凡的 library,让我们能够心得区别的编制程序范式和技术。而大家又屡屡供给不塑造不一样的类库来兑现 async action,这里有三种不一致的法门来拍卖那一个 side effects

  • Redux Thunk – (Delayed) Functions
  • Redux Promise – Promises
  • Redux Saga – Generators
  • Redux Observable – Observables
  • Redux Loop – Elm Effects

新手的话建议选取 redux thunk 来管理局地异步操作;等你慢慢的熟识整个生态及其有关的应用的时候,能够看看别的的有关类库。Redux Saga 是日前被周边接纳的豆蔻梢头种实现格局。然则,Redux Observables 近些日子也被进一层多的人所承担,那可是需求精通不少有关 rxjs 及其响应式编制程序的定义及其使用办法。

实则,全部看来,redux 生态圈的自家就生出了极其多的前端类库,真是令人应接不暇啊。但也别烦扰,那些你无需接纳的事物,自然也无需都去调整,对吧。

新建项目 ReactRedux德姆o (从新初叶卡塔尔

react-native init ReactReduxDemo

多读书一下 Redux 的达成源码

Redux 本人的源码并十分少,总共也才五七个第一文件,不超千行代码。借使您想对 Redux 尤其熟稔,那么生硬建议你要抽些时日多剖析一下他的源码。

在始发攻读的时候,也推荐部分学习摄像给你:

  • Redux 的小编 Dan Abramov 本人摄像的入门级录像 《getting-started-with-redux》 ,大家都在说摄像的很棒,可是说真的,那些对通晓贯彻原理是很有帮扶的。javascript-redux-implementing-store-from-scratch 和 javascript-redux-implementing-combinereducers-from-scratch 四个录制能够协理您了解 store 和 combineReducer 的贯彻原理。
  • 第二个鳞萃比栉的录制是《building-react-applications-with-idiomatic-redux》,你能够从当中学习到什么促成您和谐的 middleware 中间件,学完后就能够学习怎么着在 store 中使用它们。然后,你就会左右到何以采取applayMiddleware 将中间件应用到 store 中

那个摄像内容既可以够教你快速调控怎么着采用 Redux,还足以让您领悟 Redux 的落到实处原理。最后,你就能够啃一啃 Redux 的源码了,能够学学到无数幽默的编制程序观念和函数式的使用。

安装

笔者们要设置 reduxreact-redux,在尖峰中跻身到品种目录,履行安装命令:

cd ReactReduxDemo
npm install redux react-redux --save

大家来看一下体系布局与package,如下所示:

|--ReactReduxDemo
    |--__tests__
    |--android
    |--ios
    |--node_modules
    |--index.android.js
    |--index.ios.js
    |--package.json
    |--...

package.json文件

{
    "name": "ReactReduxDemo",
    "version": "0.0.1",
    "private": true,
    "scripts": {
        "start": "node node_modules/react-native/local-cli/cli.js start",
        "test": "jest"
    },
    "dependencies": {
        "react": "15.4.1",
        "react-native": "0.38.0",
        "react-redux": "^4.4.6",  // react-redux 依赖包
        "redux": "^3.6.0",        // redux 依赖包
    },
    "jest": {
        "preset": "react-native"
    },
    "devDependencies": {
        "babel-jest": "17.0.2",
        "babel-preset-react-native": "1.9.0",
        "jest": "17.0.3",
        "react-test-renderer": "15.4.1"
    }
}

接下去,大家搭建大家的种类组织,况兼,后面已经介绍, store 的创始必要reducer ,状态 state 的更新必要action。所以,为了便利未来的布局管理,大家先做如下操作:
创建 app 文件夹,
创制 app/index.js 入口文件,
创建 app/components 文件夹,
创建 app/containers 文件夹,
创办 app/reducers 文件夹(寄存全体的拆分为小的 reducer 文件),
始建 app/actions 文件夹(寄存全部的拆分为小的 action 文件)。
今昔,大家的档期的顺序构造,如下:

|--ReactReduxDemo
    |--__tests__
    |--android
    |--app
        |--actions
        |--components
        |--containers
        |--reducers
        |--index.js
    |--ios
    |--node_modules
    |--index.android.js
    |--index.ios.js
    |--package.json
    |--...    

花色布局早就搭好,接下去,大家开头

编后语

本篇内容实现,愈来愈多内容请前往在 2017 年攻读 React Redux 的部分建议(下篇)。

万后生可畏您想系统学习 React Redux 技巧栈的具备内容,请点本身前往

2 赞 1 收藏 评论

图片 5

写代码

1、稍微修改 ReactReduxDemo/index.ios.js 文件

import React, {
    Component
} from 'react';
import {
    AppRegistry,
    StyleSheet,
    View
} from 'react-native';

import RootWrapper from './app/index';     // 引入入口文件

export default class ReactReduxDemo extends Component {
    render() {
        return (
            <View style={styles.container}>
                <RootWrapper />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    }
});

AppRegistry.registerComponent('ReactReduxDemo', () => ReactReduxDemo);

2、入口文件 ReactReduxDemo/app/index.js ,改正如下:

import React, { Component } from 'react';
import {
    View,
    StyleSheet,
} from 'react-native';

import HomeContainer from './containers/home.container';  // home 容器

export default class RootWrapper extends Component{
    render(){
        return (                
                <View style={styles.wrapper}>
                    <HomeContainer />
                </View>
        );
    }
}

const styles = StyleSheet.create({
    wrapper: {
        flex: 1,
        marginTop: 20,
    },
});

容器组件 ReactReduxDemo/app/containers/home.container.js,如下:

import React, { Component } from 'react';
import {
    View,
    Text
} from 'react-native';

export default class HomeContainer extends Component{
    constructor(props){
        super(props);

    }
    render(){
        return (
            <View>
                <Text>Hello Redux !</Text>
            </View>
        );
    }
}

运作品种,如下所示:

图片 6

Paste_Image.png

使用 Redux

此地,大家所做职务如下:

  • 创建 store,并含有开头数据
  • 使用 Provider connect()
  • 展现起初数据

1、大家先创建叁个子组件 TodoListComponent 来显示测量试验数据

新建文件 ReactReduxDemo/app/components/todo-list.component.js,如下:

import React, { Component } from 'react';
import {
    Text,
    View,
    StyleSheet,
} from 'react-native';


export default class TodoListComponent extends Component{
    constructor(props){
        super(props);

    }

    render(){
        return (
            <View style={styles.wrapper}>
            {this.props.todoList.map((todo, index)=>{
                var finishStyle = {textDecorationLine:'line-through', color:'gray'};
                return (
                    <Text style={[styles.todo,todo.status&&finishStyle]}>{todo.title}</Text>
                );
            })}
            </View>
        );
    }
}


const styles = StyleSheet.create({
    wrapper: {
        paddingHorizontal: 20,
    },
    todo: {
        paddingVertical: 5,
    },
});

这里的子组件 TodoListComponent 只是用 props 接纳来自容器组件的多少,并以突显。

将容器组件 HomeContainer 稍作改过:

import React, { Component } from 'react';
import {
    View,
    Text
} from 'react-native';

import TodoListComponent from '../components/todo-list.component';  // 引入子组件

export default class HomeContainer extends Component{
    constructor(props){
        super(props);
    }

    render(){
        return (
            <View>
                <TodoListComponent todoList={[{title:'测试数据'}]} />
            </View>
        );
    }
}

运营品种,如下展现:

图片 7

Paste_Image.png

2、创建 store,并包含早先数据
校正入口文件,引进 reduxreact-reduxreducers ,定义起初数据,创建 store ,使用 Provider 包裹根组件,并带上 store 属性(供被装进的构件使用)。

ReactReduxDemo/app/index.js 文件,校勘如下:

import React, { Component } from 'react';
import {
    View,
    StyleSheet,
} from 'react-native';
import { createStore } from 'redux';        // 引入 redux 以创建 store
import { Provider } from 'react-redux';     // 引入 react-redux,使用 Provider

import reducers from './reducers/index';    // 引入 reducers

import HomeContainer from './containers/home.container';

// 这是初始数据
const initState = {
    todos: [
        {title:'吃早饭',status:true},
        {title:'打篮球',status:false},
        {title:'修电脑',status:false},
    ],
};

let store = createStore(reducers, initState);  // 创建 store

export default class RootWrapper extends Component{
    render(){
        return (
            <Provider store={store}>
                <View style={styles.wrapper}>
                    <HomeContainer />
                </View>
            </Provider>
        );
    }
}

const styles = StyleSheet.create({
    wrapper: {
        flex: 1,
        marginTop: 20,
    },
});

新建文件 ReactReduxDemo/app/reducers/index.js (作为持有 reducer 的入口),如下:

import { combineReducers } from 'redux';

// 这是一个空的 reducer , 不做任何处理,返回原始 state
function todoList(state=[], action){
    return state;
}

const reducers = combineReducers({
    todos: todoList           // 这里的 key 要与初始数据的 key 一致
});

export default reducers;

3、使用 react-redux 提供的 connect() 进行延续组件与redux。
容器组件 ReactReduxDemo/app/containers/home.container.js 文件,改过如下:

import React, { Component } from 'react';
import {
    View,
    Text
} from 'react-native';
import { connect } from 'react-redux';    // 引入 react-redux

import TodoListComponent from '../components/todo-list.component';

class HomeContainer extends Component{   // 这里,HomeContainer不再是默认export
    constructor(props){
        super(props);

    }
    render(){
        return (
            <View>
                <TodoListComponent todoList={this.props.todoList} />   // 注意,这里的 todoList 是 mapStateToProps 返回的 key  (运行时,注释会报错,请删除注释)
            </View>
        );
    }
}

// 基于全局 state ,哪些 state 是我们想注入的 props
function mapStateToProps(state){
    return {
        todoList: state.todos,  // 将全局的 state 的其中一个 key(即todos) 作为 props 注入
    }
}

export default connect(mapStateToProps)(HomeContainer);  // 连接组件并export

3、运营项目,如下呈现,则表达我们使用 redux 成功了。

图片 8

Paste_Image.png

到那边,大家成功的将 ReactRedux 连接了起来,并浮现了起来数据,
下篇中,大家会 dispatch(action卡塔尔国 更新景况操作!!!

本文由pc28.am发布于前端技术,转载请注明出处:Redux进级类别3,一步一步学习

上一篇:获得成分间隔浏览区域的偏离,获取页面成分的 下一篇:没有了
猜你喜欢
热门排行
精彩图文
  • 何以要写测验用例,的有的提议
    何以要写测验用例,的有的提议
    在 2017 年学习 React Redux 的一些建议(下篇) 2017/09/11 · JavaScript· React,Redux 原文出处: 郭永峰    在这里说一下前端开发的一个特点是更多的会涉及用户界
  • js从0开始构思表情插件
    js从0开始构思表情插件
    js从0开头考虑表情插件 2016/07/28 · JavaScript· 插件 本文小编: 伯乐在线 -陈被单。未经作者许可,禁绝转发! 应接加入伯乐在线 专辑小编。 前言: 是因为
  • 且是否滚动到头部或者底部,子元素scroll父元素
    且是否滚动到头部或者底部,子元素scroll父元素
    子元素scroll父元素容器不跟随滚动JS实现 2015/12/18 · JavaScript· 滚动 原文出处:张鑫旭    一、开场暖身 网上常见蹲来蹲去的小段子,比方说:“李代沫蹲
  • 用功率信号来支配异步流程,web播放控件
    用功率信号来支配异步流程,web播放控件
    用确定性信号来支配异步流程 2017/08/08 · JavaScript· 异步 原版的书文出处:十年踪迹    总结 大家通晓,JavaScript 不管是操作DOM,还是进行服务端职责,不
  • 聊一聊原生浏览器中的模块,动态加载JS函数
    聊一聊原生浏览器中的模块,动态加载JS函数
    聊风流浪漫聊原生浏览器中的模块 2018/07/04 · 底子技能 ·浏览器 初藳出处:记    自从ES二零一四杀青以来,大家透过 Babel等转移工具得以在等级次序中平