一、前言
上一节——redux基础知识中介绍了redux 的基本使用。
但是在实际react项目中使用redux 的话,一般不会使用原生redux ,而是会再加上react-redux 一起使用。
redux 与react-redux 并没有什么关系,redux 可以在任意地方使用,可以在react 项目中使用,也可以在vue 项目中使用,甚至可以在jQuery 项目中使用。而react-redux 是redux官方做的用于更好地与react 进行配合。
这一节,将会在前一节redux 的基础上,使用react-redux 来让我们的组件更丝滑。
二、react-redux基础
2.1 react-redux简介
react-redux 可以理解为是redux 关于react 项目的高级语法糖,他并不是redux ,只是让你的redux 代码在react 项目中更丝滑。
react-redux 中有两个重要的成员:
下面将会详细介绍一下这两部分。
2.2 Provider标签
Provider 是一个标签,他是一个react-redux 封装的标签,用来包裹根组件用的,他的作用就是可以让你的整个应用都能随时随地的拿到store 中的state 。
Provider 标签有一个参数,props 参数需要将store 传递进去,然后通过context往下传递,使每个组件都能拿到store 。
import { Provider } from 'react-redux';
import { Provider } from 'react-redux';
ReactDOM.render(
<Provider>
<App />
</Provider>
);
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider props={store}>
<App />
</Provider>
);
2.3 connect
虽然根节点外使用了Provider 标签进行了包裹,但是Provider 只是提供一个将store 往下传递的能力,想要使用到store 中的数据,就必须使用connect() 方法对组件进行包裹(加强)。
import { connect } from 'react-redux';
注意:调用connect()方法将会返回另一个方法,此时再将组件作为参数传入该方法进行包裹。
import { connect } from 'react-redux';
import ComA from './ComA';
connect()(ComA);
这里使用了函数柯里化的概念,这种写法常用的地方是在工厂函数,如果有了解过express /koa /egg.js 中间件的写法,应该就会对该种写法比较熟悉。
前面一部分connect() 通过传入参数具体定制工厂函数的工作逻辑/模式,并返回一个函数,然后再将需要传入工厂函数的参数传入,运行工厂函数。
这里第一部分connect() 方法的参数如下(按顺序):
参数名 | 类型 | 说明 |
---|
mapstateToProps(state, ownProps) | Function | 该函数会将store的数据绑定到组件上。 state : redux中的store
ownProps : 组件自己的props | mapDispatchToProps(dispatch, ownProps) | Function | 该函数返回一个对象,该对象的每个属性就是一个action,会将这些action作为props绑定到组件上。
dispatch : 就是store.dispatch
ownProps : 组件自己的props | mergeProps(stateProps, dispatchProps, ownProps) | Function | 不管是stateProps 还是dispatchProps ,都需要和ownProps merge之后才会被赋给我们的组件,通常情况下,你可以不传这个参数,connect就会使用object.assign 替代该方法 | options | Object | connect的其他配置项 |
其中,mapstateToProps 和mapDispatchToProps 是需要特别掌握的,这两个在开发过程中使用的频率最高也是最重要的部分。
import { connect } from 'react-redux';
import ComA from './ComA';
const mapstateToProps = (state, ownProps) => {
}
const mapDispatchToProps = (dispatch, ownProps) => {
}
connect(mapstateToProps, mapDispatchToProps)(ComA);
其实也想把mapstateToProps 和mapDispatchToProps 使用示例贴上来,但是好像脱离实际使用的这部分代码反而让人看得云里雾里的。不如我们直接上项目吧。
三、Show me the code
本项目还是用一个计数器来进行展示吧。包含两个组件
- 按钮组件:包含【+】和【-】按钮,点击按钮,显示组件显示内容也会随之改变
- 显示组件:负责显示当前计数,默认值为0
3.1 新建项目
老样子,还是使用CRA 工具来创建一个react项目:
# 创建项目
npx create-react-app react_redux_demo
# 进入项目目录
cd react_redux_demo
3.2 安装依赖
所需安装的依赖有两个:
npm i redux react-redux --save
3.3 添加reducer
和上一节一样的操作,在src 目录下添加一个文件夹src/reducer ,里面新建一个index.js 文件。
const initState = {
value: 0
};
const reducer = (state = initState, action) => {
switch(action.type) {
case 'add':
return { value: state.value + 1 };
case 'decrese':
return { value: state.value - 1 };
default:
return state;
}
}
export default reducer;
3.4 添加store
和上一节一样的操作,在src 目录下添加一个文件夹src/store ,里面新建一个index.js 文件。
import { createStore } from 'redux';
import reducer from '../reducer';
const store = createStore(reducer);
export default store;
3.5 修改index.js
因为根节点是在src/index.js 文件中,所以直接到这里来进行一个Provider 的包裹就行。当然,src/app.js 中包裹也是没有问题的,但是要保证你的Provider 标签把你要用到store 的部分完全包裹起来。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
3.6 完成按钮组件
按钮组件包含以下几部分:
- 包含【+】和【-】按钮
- 点击按钮,显示组件显示内容也会随之改变(修改
store )
在src 目录下新建一个Components/Button 文件夹,并在其下创建index.js 文件夹
src/Components/Button/index.js 文件基本内容
function Button(props) {
return (
<>
<button> + </button>
<br />
<button> - </button>
</>
);
}
export default Button;
import { connect } from 'react-redux';
function Button(props) {
return (
<>
<button> + </button>
<br />
<button> - </button>
</>
);
}
const mapDispatchToProps = (dispatch) => {
return {
add: () => {
dispatch({ type: 'add' });
},
decrese: () => {
dispatch({ type: 'decrese' });
}
};
};
export default connect(null, mapDispatchToProps)(Button);
import { connect } from 'react-redux';
function Button(props) {
const addHandler = () => {
props.add();
};
const decreseHandler = () => {
props.decrese();
};
return (
<>
<button onClick={addHandler}> + </button>
<br />
<button onClick={decreseHandler}> - </button>
</>
);
}
const mapDispatchToProps = (dispatch) => {
return {
add: () => {
dispatch({ type: 'add' });
},
decrese: () => {
dispatch({ type: 'decrese' });
}
};
};
export default connect(null, mapDispatchToProps)(Button);
3.7 完成计数器显示组件
该组件只包含一个功能:
首先,在src 目录下新建一个Components/Counter 文件夹,并在其下创建index.js 文件夹
src/Components/Counter/index.js 文件基本内容
function Counter(props) {
return (
<div></div>
);
}
export default Counter;
import { connect } from 'react-redux';
function Counter(props) {
return (
<div>{props.value}</div>
);
}
const mapstateToProps = (state) => {
return state;
};
export default connect(mapstateToProps)(Counter);
3.8 将组件添加到app.js中
在src/app.js 中,添加上述完成的两个组件:
import Button from './Components/Button';
import Counter from './Components/Counter';
function App() {
return (
<div className="App">
<Button />
<Counter />
</div>
);
}
export default App;
至此,一个完整的计数器就完成了。
|