序
本人工作之余的闲暇时间还是很充裕的。在完成经理安排的任务后,基本上都是在自学,主要是阅读各种技术文档、浏览博客、运行别人写的一些前端demo并观赏与赞叹。 同学的带领下,我们决定决定做一个react版的音乐播放SPA(Single Page web Application)。
首选,模仿网易云的界面,因为是程序猿最爱的音乐播放器,不解释!然而,分析网易云的数据请求时,貌似全是403。github上有大牛提供了网易云音乐的一些接口,非常好。所以,对于数据接口,我们最后选择了“哈喽,酷狗!”。
阅读了redux的文档后,并参与了一个练手项 的部分开发后,通过自己的理解,整理了这篇文档。
初学,所以一定会有不详或者错误的地方。
参考文档
开发这个项目,我参阅的学习文档如下:
流程图解
通过我自己的理解方式,简单地整理了react、redux、react-redux三者之间的关系图,如下:
通过代码,梳理redux、react-redux
注:下面代码只列出搜索功能的关键部分,
1. Provider
react-redux提供的Provider
组件,可以让容器组件取得state
。
src/index.js
import configureStore from './stores' const store = configureStore() <Provider store={store}> <Router history={browserHistory} routes={routers} /> </Provider>
上面代码中,Provider
使得Router
的所有子组件可以取得state
。
import configureStore from './stores'
为redux的store,如下:
src/store/index.js
import reducers from '../reducers/index'; export default function(initialState) { let createStoreWithMiddleware // 判断环境是否logger if (process.env.NODE_ENV === 'production') { createStoreWithMiddleware = applyMiddleware(thunk)(createStore); }else{ //开发环境在console可以看到整个状态树的实时日志 const logger = createLogger(); createStoreWithMiddleware = applyMiddleware(thunk,logger)(createStore); } let store = createStoreWithMiddleware(reducers, initialState); return store; };
2. react:Component
src/containers/search.js
import React, { Component, PropTypes } from 'react' import { connect } from 'react-redux' import { searchHotAPI,searchResultAPI,clearSearchResultAPI} from '../actions/search' class Search extends Component { constructor(props) { super(props); } componentDidMount(){ const { dispatch } = this.props dispatch(searchHotAPI()) } searchEvt(keyword,page=1){ const { dispatch } = this.props; keyword = keyword || this.refs.keyword.value if(keyword!=''){ dispatch(searchResultAPI(keyword, page)); }else{ dispatch(clearSearchResultAPI()); } this.refs.keyword.value = keyword; } render() { const { dispatch,controll,search } = this.props; return ( <div className='root' style={{fontSize:'1.2rem'}}> //... </div> ) } } function map(state) { return { search: state.search, controll: state.music.controll } } export default connect(map)(Search)
react-redux的connect
方法,用于从 UI 组件生成容器组件。
上面代码中,connect(map)(Search)
使得组件Search
可以通过props
取得map
返回的数据。
dispatch(searchHotAPI())
和dispatch(clearSearchResultAPI())
,获取数据并分发action。
3. redux
src/actions/search.js
import Config from '../config' import { spin,spinHidden } from './spin' import api from '../api' import Storage from '../storage' //定义常量 export const SEARCH_HOT = 'SEARCH_HOT' export const SEARCH_RESULT = 'SEARCH_RESULT' //actionCreator,这里是一个函数,返回action对象 const searchHot = (obj) => {return {type:SEARCH_HOT, obj}} const searchResult = (obj) => {return {type:SEARCH_RESULT, obj}} //搜索热门关键字 export function searchHotAPI(){ return async dispatch => { try{ let hots = await api( Config.searchHotAPI ); dispatch(searchHot(hots.data.info)); } catch(error) { console.log(error); } } } //通过关键字搜索 export function searchResultAPI(keyword,page){ return async dispatch => { try { let result = await api( Config.searchResultAPI, 'get', {keyword,page} ); //搜索历史存到localStorage setSearchHistory(keyword); dispatch(searchResult(result.data.info)); } catch(error) { console.log(error); } } }
上面代码中,searchHot
和searchResult
都是Action creator,即分别返回一个action。
action是一个带有type关键字的对象,如{type:SEARCH_HOT, obj}
和{type:SEARCH_RESULT, obj}
。
searchHotAPI
和searchResultAPI
分别返回一个获取数据并分发action的异步函数,一般在容器组件里会调用。
src/reducer/search.js
import { combineReducers } from 'redux' import { SEARCH_HOT,SEARCH_RESULT } from '../actions/search' function hots(state = [], action){ switch(action.type) { case SEARCH_HOT: return action.obj; default: return state; } } function result(state = [], action){ switch(action.type) { case SEARCH_RESULT: return action.obj; default: return state; } } const Reducers = combineReducers({ hots,result, }) export default Reducers
上面代码中,hots
函数收到名为SEARCH_HOT
的 Action 以后,就返回一个新的 State,作为热门搜索的结果。
在src/store/index.js
中,开发环境下,引入了中间件redux-logger
的createLogger
,在浏览器console可以观察到每次reducer的结果,如下:
src/reducer/index.js
import { combineReducers } from 'redux' //... import search from './search' const reducers = combineReducers({ //... search, }) export default reducers
Reducer 是一个函数,它接受 Action 和当前 State 作为参数,返回一个新的 State,然后View发生变化。 combineReducers
将多个拆分的reducer合并。