阮大师写入门教程能力一流。
首推它的Redux三篇入门文章。
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.htmljavascript
这三篇文章介绍了,
Redux的基本概念和API,异步操做,以及如何跟React相结合。
文章写得不错,但实践起来仍是略显繁琐。html
下面提出我本身对Redux结合React使用的思考。java
使用ramda库组合自定义中间件。
这使得代码更灵活和透明。react
异步操做也结合ramda库。
能够不用引入第三方redux-thunk
,redux-promise
中间件。
使用ramda库更方便组合异步操做。webpack
state以React组件的state为准。
redux的state只是辅助计算出React组件的state。web
往store注入trigger函数,用来setState更新React组件。redux
在线demo
示例代码以下:
index.htmlpromise
<!doctype html> <html> <head> <meta charset="utf-8"/> </head> <body> <h1>Hello world</h1> <div id="app"></div> <script src="index.js"></script> </body> </html>
index.jsapp
import React from 'react'; import ReactDOM from 'react-dom'; import store from './store.js'; import {connect} from './connect.js'; class Test extends React.Component { constructor(props) { super(props); this.state = { value:0, otherNum:0, asyncing:false }; } dispatch(obj){ obj.state= this.state; store.dispatch(obj); } setOtherData(){ this.dispatch({ type: 'Other' }); } setData(){ this.dispatch({ type: 'INCREMENT' }); } async(){ this.dispatch({type: 'Loading' }); this.dispatch({ type: 'ASYNC'}); } componentDidMount(){ //store.dispatch({type: 'Init'}) } render() { const t = this; console.log('render', store.getState(), t.state); const {value ,asyncing,otherNum } = t.state; return ( <div> <div>数字:{value}</div> <div onClick={t.setData.bind(this)}>点我+1</div> { (()=>{ if(asyncing){ return (<div>异步加载中</div>); } else{ return (<div onClick={t.async.bind(t)}>点我异步+10</div>); } })() } <br /> <div onClick={t.setOtherData.bind(this)}>点我其余数字+1</div> <div>其余数字:{otherNum}</div> </div>); } } const NewTest = connect(store)(Test) ; ReactDOM.render( <NewTest />, document.getElementById('app') ) module.exports = NewTest;
store.jsdom
import { createStore } from 'redux'; import R from 'ramda'; const isPromise = function(e){ return !!e&&typeof e.then=="function"; }; const setTimeout1 = R.curry(function( state ){ return new Promise(function(resolve, reject){ setTimeout(function(){ resolve(state+ 10); },1000); }) }); // reducer,仅用于计算。 function counter(state = {}, action) { if(isPromise(state)){ state = {}; } state = R.merge(state, action.state); console.log('reducer中的state',state); switch (action.type) { case 'Init': return action.state; case 'INCREMENT': state.value = state.value + 1; return state case 'ASYNC': return R.composeP( setTimeout1)(state.value); case 'Loading': return {asyncing: true} case 'Other': return {otherNum: state.otherNum+1}; default: return state } } let store = createStore(counter); // subscribe,可用于执行含有反作用的操做。 store.subscribe((e) =>{ console.log('subscribe',store, store.getState(),e, this); let state = store.getState(); if(isPromise(state)){ state.then(function(num){ store.trigger({value: num, asyncing:false }); }) } else{ store.trigger(store.getState()); } }) module.exports = store;
connect.js
import {type} from 'ramda'; exports.connect = function (listenable, context) { if(type(listenable) !== 'Object'){ throw new Error('connect function\'s argument is not a object'); } listenable.trigger = function (obj,fn) { this.setState(obj || {}, fn); }; listenable.getReactState = function(){ return this.state; }; return function(otherReactClass){ return class baseReactClass extends otherReactClass { constructor(){ super(); } componentDidMount(...args) { context = context || this; listenable.trigger = listenable.trigger.bind(context); listenable.getReactState = listenable.getReactState.bind(context); super.componentDidMount(); } componentWillUnmount() { listenable.trigger = null; super.componentWillUnmount(); } } } }