>

的一些建议,ReactNative项目源码分析4

- 编辑:至尊游戏网站 -

的一些建议,ReactNative项目源码分析4

在 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提供了分化的管理方式。

图片 1对于学习 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.

全局 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目录下是登入页面,提供了经过推特(TWTR.US)(TWT兰德安德拉.US)帐号登入F8app的成效
  • rating目录下是投票和问卷相关的页面
  • reduces目录是redux Reducer相关的文件。Redux有且独有贰个State状态树,为了防止这一个情景树变得特别复杂,Redux通过 Reducers来担当管理整个应用的State树,而Reducers能够被分为多个个Reducer。
  • store目录下是redux store相关的公文
  • tabs目录下是App 4个tab页面包车型地铁源文件
    不论什么事目录构造划分还是相比较合理的。

品种目录怎么样协会

那篇小说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卡塔 尔(英语:State of Qatar)。那么,基于那样的思辨,大家的目录就能够成为那样了:

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 (等同于回调参数) -> 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卡塔尔国效能。

取名约定

在软件编程中命名可正是意气风发件令人脑瓜疼的作业,那跟给孩子命名同样费事,哈哈。合适的命名是促成可维护性、易于理解的代码的最棒实践,React

  • Redux 的使用中提供了大气的束缚来扶植我们团队代码,並且不会在命名上师心自用。无论你的函数封装在 reducer 照旧 component 中,在action creator 或是 selector 中,你都应当有三个命名约束,並且在强大应用在此以前就明确什么命名,不然平常会让大家陷入波谲云诡的回调弄整理重构个中。

而笔者习于旧贯为每一种类其余函数都增加多少个前缀。

  • 在组件的callback中,为每一个函数都抬高 on 作为前缀,举例 onCreateEvoqueplay
  • 在转移 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卡塔 尔(英语:State of Qatar)智能组件的职责就如COO同样,可是比起 Flux 中的剧中人物,Redux 对经营的天职有了更加多的定义:

  • 智能组件担当全部的 action 相关的劳作。如若智能组件里包罗的三个木偶组件需求接触一个action,智能组件会通过 props 传四个 function 给木偶组件,而木偶组件能够在必要触发 action 时调用那一个 function。
  • 智能组件不定义 CSS 样式。
  • 智能组件差不离不会发生自个儿的 DOM 节点,他的劳作是集体若干的玩偶组件,由木偶组件来扭转最后的 DOM 节点。

跟踪状态的改动

在相连迭代中的应用免不了定义大批量的 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重回五个函数,并且以此函数第二个参数是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;

尽大概让 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,照片墙(TWT牧马人.US)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对象。

单一数据源原则

格式化之后的多寡能够帮忙您按一块的形式来管理 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登入Facebook帐号的功能。
签到涉及的代码有actions/types.js(定义了富有的Action事件), actions/login.js(达成登录专门的学问逻辑,与服务器交互卡塔 尔(英语:State of Qatar),js/reducers/user.js(完成对客户相关情状的简政放权)。
签到的输入是js/tabs/schedule/logIn.js,142行定义了<LoginButton source="My F8" /> ,LoginButton组件封装了登入UI相关的逻辑。
点击LoginButton后会调用logIn函数,logIn函数会调用logInWith照片墙(Facebook)举办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的语法。
logInWithFacebook的落到实处在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;
  };
}

登入是调用FacebookSDK举办登入,logInWith照片墙是个异步方法,用到了ES6的async,
async function _logInWithFacebook(source: ?string): Promise<Array<Action>> {...}
再次来到值是个Promise,在then方面里面异步调用loadFriendsSchedules,loadSurveys。
这几个方法会继续倡议数据,并更新store,进而让页面更新。

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 、React + Redux 可能其余前端框架,你总会再三的牵线更为快速的代码组织方式,恐怕是大器晚成对很好的设计形式。

倘令你的行使中的组件十分多,你能够找到二个更加好的措施来分别和组织木偶组件和容器组件,你会开掘她们之间的关联并做一些公家的抽取;要是你还不曾接收特别的命名节制,你也得以在重构的时候去做那几个业务。

参考小说

  • Redux 华语文书档案
  • 《看漫画,学 Redux》 —— A cartoon intro to Redux
  • redux源码安详严整
  • 运用Redux管理你的React应用
  • 知道 React,但不知道 Redux,该怎么简单明了的理解Redux
  • 学习 redux.js 的 流水账

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 生态圈的自家就发生了比超多的前端类库,真是令人接应不暇啊。但也别烦闷,那多少个你无需动用的事物,自然也无需都去调整,对啊。

多读书一下 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 的源码了,能够学学到广大相映成辉的编制程序观念和函数式的行使。

编后语

本篇内容完毕,更多内容请前往在 2017 年学习 React + Redux 的局地建议(下篇卡塔 尔(英语:State of Qatar)。

假定你想系统学习 React + Redux 技巧栈的兼具剧情,请点自个儿前往

2 赞 1 收藏 评论

图片 2

本文由技术教程发布,转载请注明来源:的一些建议,ReactNative项目源码分析4