Faster, Higher, Stronger
更快,更高,更强

新的征程——React Native

本月18日,就是这么巧,是我农历生日的那一天,到公司另外一个项目部进行了一个简单的面试,虽然面试表现很水,但是领导放我进React Native项目团队了。

第一天在公司下代码装依赖,但是怎么装都装不好,怀疑是网络问题,后面回到家一装就装好了,但是还是跑不起来,第二天发现好像还有些东西必须是要在公司网络里才能下载,当然下了也还是没在ios模拟器上跑起来,后来在两个同事的帮助下终于是跑了起来。

第二天下午和第三天(也就是今天),一直在看项目代码,边看代码边查文档。果然是每次跟同行接触都有新的收获。这两天把flow(静态类型检查工具)和redux的官方文档大概读了一遍,flow是第一次接触,redux因为以前其实已经看过很多遍了只是一直没用到看了又都忘了,所以这次看起来很顺利。React Native的文档内容有点多,只能边看代码边看文档慢慢来。

flow这个东西,感觉就算是不具备自动检测能力,仅仅作为一种类型注释来给开发者“阅读”,效果也是不错的。

redux+react-redux

大体的流程可以这么说:

  • 如果用“做什么”来打比方,action就是“什么”,dispatch就是“做”,只有“做”了才是真真实实地发生了点“什么”;
  • 但是程序不知道你的action对象是干嘛的,你需要解释,reducer的作用就是解释什么action会产生什么样的新state(不能修改旧state);
  • redux暴露了一个combineReducers方法,可以用来将多个reducer进行合并(根reducer只能有一个,只能是一颗reducer主树上挂很多子reducer);
  • store是核心,把state、action、dispatch、reducer、subscribe等集成在一起,redux提供了一个createStore的方法,store = createStore(one_reducer, initial_state),获取state用store.getState(),派发action用store.dispatch(action);
  • react-redux提供了一个Provider组件,用store属性值为store的Provider组件包含根组件后,就可以在container组件上获取到store;
  • react-redux暴露了一个connect方法,可以通过它将store里的state、dispatch对应到组件的属性props上;
  • 除了很小且样式与功能耦合度较大的组件外,尽量抽出container组件和presentation组件;
  • redux提供了applyMiddleware方法来应用中间件,redux-thunk暴露的中间件可用于创建异步的action。
container组件和presentation组件分开的情况:
import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.filter === state.visibilityFilter
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch(setVisibilityFilter(ownProps.filter))
    }
  }
}

const FilterLink = connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

export default FilterLink
container组件和presentation组件不拆开的情况:
import React from 'react'
import { connect } from 'react-redux'
import { addTodo } from '../actions'

let AddTodo = ({ dispatch }) => {
  let input

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault()
          if (!input.value.trim()) {
            return
          }
          dispatch(addTodo(input.value))
          input.value = ''
        }}
      >
        <input
          ref={node => {
            input = node
          }}
        />
        <button type="submit">
          Add Todo
        </button>
      </form>
    </div>
  )
}
AddTodo = connect()(AddTodo)

export default AddTodo
关于异步action的代码示例:

index.js:

import thunkMiddleware from 'redux-thunk'
import { createLogger } from 'redux-logger'
import { createStore, applyMiddleware } from 'redux'
import { selectSubreddit, fetchPosts } from './actions'
import rootReducer from './reducers'

const loggerMiddleware = createLogger()

const store = createStore(
  rootReducer,
  applyMiddleware(
    thunkMiddleware, // lets us dispatch() functions
    loggerMiddleware // neat middleware that logs actions
  )
)

store.dispatch(selectSubreddit('reactjs'))
store
  .dispatch(fetchPosts('reactjs'))
  .then(() => console.log(store.getState()))

actions.js

import fetch from 'isomorphic-fetch'

export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
  return {
    type: REQUEST_POSTS,
    subreddit
  }
}

export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
  return {
    type: RECEIVE_POSTS,
    subreddit,
    posts: json.data.children.map(child => child.data),
    receivedAt: Date.now()
  }
}

// Meet our first thunk action creator!
// Though its insides are different, you would use it just like any other action creator:
// store.dispatch(fetchPosts('reactjs'))

export function fetchPosts(subreddit) {
  // Thunk middleware knows how to handle functions.
  // It passes the dispatch method as an argument to the function,
  // thus making it able to dispatch actions itself.

  return function (dispatch) {
    // First dispatch: the app state is updated to inform
    // that the API call is starting.

    dispatch(requestPosts(subreddit))

    // The function called by the thunk middleware can return a value,
    // that is passed on as the return value of the dispatch method.

    // In this case, we return a promise to wait for.
    // This is not required by thunk middleware, but it is convenient for us.

    return fetch(`https://www.reddit.com/r/${subreddit}.json`)
      .then(
        response => response.json(),
        // Do not use catch, because that will also catch
        // any errors in the dispatch and resulting render,
        // causing an loop of 'Unexpected batch number' errors.
        // https://github.com/facebook/react/issues/6895
        error => console.log('An error occured.', error)
      )
      .then(json =>
        // We can dispatch many times!
        // Here, we update the app state with the results of the API call.

        dispatch(receivePosts(subreddit, json))
      )
  }
}

面试的时候,有问到一个问题,switch组件(滑动开关组件)应该用props还是states,领导说是要用states,不过个人觉得应该是用props,因为如果这个组件要是作为第三方组件供他人使用的话,肯定不会取改组件内部的代码的,感觉还是通过props传两个值(一个是表示开关状态的flag,一个是用于修改开关flag的值的函数)比较适合,我vue项目里是这么去弄的,不知道是不是我想错了-_-。

感觉代码还需要再花点时间看,或许慢慢写点简单的可能已经可以了。其实比较怕的是版本控制出错,因为以前都是我一个人的仓库,不怎么会遇到多人协作管理一个仓库的情况。

参考:
  • http://redux.js.org/docs/advanced/AsyncActions.html
赞(0) 打赏
未经允许不得转载:峰间的云 » 新的征程——React Native

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏