需求:
- 页面上有一个数字 n ,一个按钮 +1,按钮 -1
- 点击 +1 之后 n 就会加 1
点击 -1 之后 n 就会减 1
以下将分别展示使用 VanillaJS + Redux、React + Redux、React + Redux + React-Redux 的做法。这里是Redux官方文档地址 。
1. 原生JS+Redux
index.html (引入redux)
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/redux/4.0.4/redux.min.js"></script>
</body>
script.js
const stateChanger = (state = 0, action) => {
switch (action.type) {
case "add":
return state + action.payload; //2 根据操作生成新的 state, 触发一个事件
case "minus":
return state - action.payload;
default:
return state;
}
};
const store = Redux.createStore(stateChanger);
function render() {
let app = document.querySelector("#app");
app.innerHTML = `
<div>
你点击了 <span id="value">${store.getState()}</span> 次
</div>
<div>
<button id="add" onclick="add()">+1</button>
<button id="minus" onclick="minus()">-1</button>
</div>
`;
}
render();
store.subscribe(render); //3 接收到事件,重新 render
function add() {
store.dispatch({ type: "add", payload: 1 }); // 1 dispatch 一个 action
}
function minus() {
store.dispatch({ type: "minus", payload: 1 });
}
2. React + Redux
使用官方提供的 create-react-app
来创建应用。
//App.js
class App extends React.Component {
add1(){
this.props.onAdd1()
}
minus1(){
this.props.onMinus1()
}
render(){
return(
<div>
<div>
你点击了 <span id="value">{this.props.value}</span> 次
</div>
<div>
<button id="add1" onClick={this.add1.bind(this)}>+1</button>
<button id="minus1" onClick={this.minus1.bind(this)}>-1</button>
</div>
</div>
)
}
}
export default App;
//index.js
function stateChanger(state = 0, action) {
switch (action.type) {
case 'add':
return state + action.payload
case 'minus':
return state - action.payload
default:
return state
}
}
function render() {
ReactDOM.render(<App value={store.getState()}
onAdd1={() => { store.dispatch({ type: 'add', payload: 1 }) }}
onAdd2={() => { store.dispatch({ type: 'minus', payload: 1 }) }}
/>, document.getElementById('root'));
}
const store = createStore(stateChanger)
render()
store.subscribe(() => {
render()
})
代码怎么变多了... 但结合React使用也是有好处的,: ) React是局部更新。
但 store
怎么要一直传啊。
为了解决这个问题, React 社区又推出了一个新的工具:React-Redux 。
注意:Redux 和 React-Redux 是两个不同的东西哦
3. React + Redux + React-Redux
React-Redux 能够使你的 React 组件从Redux store中读取数据,并且向
store
分发actions
以更新数据。
React-Redux 中的API不多,这里使用 Provider
和 connect()
就够用了。
重要API
Provider 标签
store
可以传给 Provider
里的每一个组件。
<Provider store={store}>
<App />
</Provider>,
connect 函数
将 store
里的数据和 dispatch action
和当前组件绑定,使得该组件可以自由访问和修改 store
。
// 将部分 store 里的 state 映射到当前组件的 props 上
function mapStateToProps(state){
return {
n: state.n
}
}
// 将 dispatch action 相关操作映射到 props 上
function mapDispatchToProps(dispatch) {
return {
add1: ()=> dispatch({type:'add', payload: 1})
}
}
//将两个参数合并起来,作为 props 传给 App
export default connect(mapStateToProps,mapDispatchToProps)(App);
解释一下 connect( )( )
:怎么函数调用时可以有2个( )
function connect(a) {
return function fn(b) {
console.log(a + b)
}
}
connect(1)(2) //3
其中,connect(1)
称为偏函数。
connect
函数 先接受一部分参数,再接收一部分,并把第一个参数和第二个参数结合起来(传出去)。
完整代码:
//index.js
const reducer = (state = { n: 0 }, action) => {
switch (action.type) {
case "add":
var newState = { n: state.n + action.payload };
return newState;
case "minus":
return {
n: state.n - action.payload
};
default:
return state;
}
};
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
//App.js
class App extends React.Component {
render() {
return (
<div className="app">
<div>
你点击了 <span id="value">{this.props.n}</span> 次
</div>
<div>
<button id="add1" onClick={this.props.add1.bind(this)}>+1</button>
<button id="minus1" onClick={this.props.minus1.bind(this)}>-1</button>
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
n: state.n
}
}
function mapDispatchToProps(dispatch) {
return {
add1: () => dispatch({ type: 'add', payload: 1 }),
minus1: () => dispatch({ type: 'minus', payload: 1 }),
}
}
//将两个参数合并起来,作为 props 传给 App
export default connect(mapStateToProps, mapDispatchToProps)(App);
4. 一些概念
Redux
store
:存放全局数据的一个东西,但是要通过 store.getState()
来获取全局数据
state
:全局数据
其实,新名词也只不过是旧概念换个名字罢了:
data
: store.getState()
event(name, data)
: action(Type, Payload)
trigger
: dispatch
on
: subscribe
例子里的stateChanger
: reducer
React-Redux
Provider
: 在这个标签里传入 store
后,通过某些方法所有组件都可以访问到 store
mapStateToProps
:将 store
里的数据放在这个组件的 props 上
mapDispatchToProps
:将需要调用 dispatch
的函数放在这个组件的 props 上
connect
:将上面两个东西和这组件联系起来