本月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