和往常一样,本文的所有文件—-仍然是基于 create-react-app脚手架 创建的项目的 ./src/ 文件夹下
react-redux
- npm install react-redux –save
- 有了react-redux,就可以忘记 store.subscribe函数了,记住reducer action和dispatch即可。
- React-redux提供了
Provider
和connect
两个接口来链接
//在index.js中
//第一步
import { Provider } from 'react-redux';
//第二步
ReactDOM.render(
(//还可以通过<App store = { store }>传递store>
<Provider store = { store }>
<App />
</Provider>
),
document.getElementById('root')
);
//在app.js中 第三步
import { connect } from 'react-redux';
import { addGun, removeGun,addGunAsync } from './index.redux';
//第四步
const mapStatetoProps= state=>({num: state });
const actionCreators = { addGun, removeGun,addGunAsync };
App = connect(mapStatetoProps, actionCreators)(App);
//然后就可以直接在this.props中使用addGun, removeGun,addGunAsync,num这几个属性了,在下面贴出的源码文件中有明确的代码。
cennect(mapStatetoProps,actionCreators )函数可以用装饰器的方式来书写
- 由于 需要额外的插件,需要执行
npm run eject
,才能自行配置。 npm install babel-plugin-transform-decorators-legacy
- Package.json 里面的 babel 字段加上plugins配置
"babel": {
"presets": [
"react-app"
],
"plugins": ["transform-decorators-legacy"]
}
然后就可以用 @connect
的方式来写了,效果可以看下面源码中的效果对比,非常优雅!
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { counter } from './index.redux';
import App from './app';
//store
const store = createStore(counter, applyMiddleware(thunk));
//get inititalState
const init = store.getState();
console.log(init);
//store.subscribe所需的参数为
store.subscribe(render);
function render() {
ReactDOM.render(
(
<Provider store = { store }>
<App />
</Provider>
),
document.getElementById('root')
);
}
render();
//每次调用store.dispatch就会触发store.subcribe, 通常store.dispatch放在最后
//app.js
import React from 'react';
import { connect } from 'react-redux';
//引入三个action创建函数,其中有一个是一个dispatch返回一个异步函数,这个异步函数再执行一个dispatch的定时任务
import { addGun, removeGun, addGunAsync } from './index.redux';
//mapStatetoProps是为connect函数的 第一个 参数而准备的
/* const mapStatetoProps = state=> {
return { num: state }//将num属性映射到this.props,this.props则拥有了this.props.num属性。
} */
//actionCreators是为connect函数的 第二个 参数而准备的
/*
const actionCreators = { addGun, removeGun, addGunAsync };
App = connect(mapStatetoProps, actionCreators) (App);
*/
@connect(//上面6-15行的代码,可以用一个@connect的装饰器来替换,这样代码会更加简洁和优雅
state=>({num:state}),
{ addGun, removeGun, addGunAsync }
)
class App extends React.Component {
// constructor(props) {
// super(props);
// }
render() {
return (
<div>
<h1>
现在有机枪 { this.props.num } 把
</h1>
<button onClick={this.props.addGun}> 老兵申请武器</button>
<button onClick={this.props.removeGun}> 上交武器</button>
<button onClick={this.props.addGunAsync}> 新兵试用两秒 再发武器</button>
</div>/*onClick后面的值必须是纯函数的形式,而不能是一段可执行代码*/
)
}
}
//mapStatetoProps是为connect函数的 第一个 参数而准备的
const mapStatetoProps = state=> {
return { num: state }//将num属性映射到this.props,this.props则拥有了this.props.num属性。
}
//actionCreators是为connect函数的 第二个 参数而准备的
const actionCreators = { addGun, removeGun, addGunAsync };
App = connect(mapStatetoProps, actionCreators) (App);
export default App;
相对于上一篇文章,index.redux.js完全没有修改
//index.redux.js
const addGUN = 'addGUN';
const removeGUN = 'removeGUN';
//reducer
export function counter(state=10, action) {
switch(action.type) {
case addGUN:
return state+1;
case removeGUN:
return state-1;
default :
return state
}
}
//action创建函数
export function addGun() {
return { type: addGUN }
}
export function removeGun() {
return { type: removeGUN }
}
export function addGunAsync() {
return (dispatch)=>{
setTimeout(()=>{
dispatch(addGun())
},2000)
}
}
//这个文件仅仅存放了 reducer 和 action创建函数