版权声明: https://blog.csdn.net/weixin_33768153/article/details/82842536
为了方便操作,我们在本篇文章将完成编写react-redux的编写,事先Provider,connect组件,并将store映射到this,减少文件引入
react-redux
在src目录下新建目录react-redux,并在新建的目录内创建一下文件
1.connect.js 仓库和组件的链接
2.context.js 上下文对象
3.index.js 导出文件
4.Provider.js
-
index.js内容
暴露出需要的模块
import Provider from './Provider' import connect from './connect' export{ Provider, connect }
-
context.js文件内容
// 创建上下文对象,并导出给外部使用 import React from 'react'; let {Provider, Consumer} = React.createContext() export { Provider, Consumer }
-
connect.js内容
思路:导入对象,拿到上下文的Consumer对象,以及自动绑定actions的方法bindActionCreators
代码实现思路:
1.导出一个函数组件 2.该组件接受三个参数: connect 实现的是仓库和组件的链接,mapStateToProps 是一个函数 把状态映射为一个属性对象,mapDispatchToProps 是一个函数,把dispatch方法映射为一个属性对象 3.返回一个高阶函数,这个参数接收一个参数,参数为一个react组件 4.在返回的组件内部新建一个类组件Propxy组件,这个组件主要实现上下文传递,组件挂在以后订阅state的事件,组件卸载的时候销毁订阅,
import React, {Component} from 'react'; import {Consumer} from './context' import { bindActionCreators } from '../redux'; /** * connect 实现的是仓库和组件的链接 * mapStateToProps 是一个函数 把状态映射为一个属性对象 * mapDispatchToProps 是一个函数,把dispatch方法映射为一个属性对象 */ export default function (mapStateToProps, mapDispatchToProps) { return function (Compon) { // 在这个组件实现仓库和组件的链接 class Propxy extends Component{ state = mapStateToProps(this.props.store.getState()) componentDidMount () { // 组件挂在之后订阅世界 this.unsubscribe = this.props.store.subscribe(() => { this.setState(mapStateToProps(this.props.store.getState())) }) } componentWillUnmount () { // 组件卸载之前关闭订阅 this.unsubscribe() } render () { let actions = {} // 如果是一个mapDispatchToProps 是一个函数,执行后得到属性对象 if (typeof mapDispatchToProps === 'function') { actions = mapDispatchToProps(this.props.store.dispatch) } else { // 如果是mapDispatchToProps是一个对象,需要我们自己绑定 actions = bindActionCreators(mapDispatchToProps, this.props.store.dispatch) } return <Compon {...this.state} {...actions} /> } } return () => ( <Consumer> { value => { return <Propxy store={value.store} /> } } </Consumer> ); } }
-
Provider.js内容
/** * 是一个组件,用来接收store,经在经过他的手,通过context api传递给所有的子组件 */ import React, {Component} from 'react' import {Provider as StoreProvider, Consumer} from './context' import PropTypes from 'prop-types' export default class Provider extends Component{ // 如果有人想使用这个组件,必须提供一个redux仓库属性 static propTypes = { store: PropTypes.object.isRequired } render () { let value = {store: this.props.store} return ( // 使用Provider提供可以跨组件使用的上下文对象 <StoreProvider value = {value}> {this.props.children} </StoreProvider> ) } }
components目录下的修改
- Counter.js的修改
import React from 'react';
import actions from '../store/actions/counter'
import { connect } from '../react-redux'
// 我们使用方法映射以后,不在需要如下繁琐的绑定
// import {bindActionCreators} from '../redux'
// import store from '../store'
// 绑定action,自动派发事件给store
// let action = bindActionCreators(actions, store.dispatch)
class Counter extends React.Component {
// 经过方法映射以后,不需要这些状态,可以直接在this.props拿到属性
// state = store.getState().counter
// componentDidMount() {
// store.subscribe(() => this.setState({
// number: store.getState().counter.number
// }))
// }
render () {
return (
<div>
<p>Counter: {this.props.number}</p>
{/* 传参调用方式 */}
<button onClick={() => this.props.add(1)}>+</button>
<button onClick={() => this.props.minus(2)}>-</button>
</div>
)
}
}
// 把仓库种的完整状态映射为属性对象 state.counter.number
let mapStateToProps = state => state.counter
// // 把dispatch映射银组建的属性对象 这个方法可以直接使用actions替代
// let mapDispatchToProps = dispatch => ({
// add1 () {
// dispatch({type: 'ADD', payload: 1})
// },
// MINUS () {
// dispatch({type: 'MINUS', payload: 1})
// }
// })
// 映射store属性
export default connect(mapStateToProps, actions)(Counter)
- Counter1.js内容修改如下
import React from 'react';
import store from '../store'
import actions from '../store/actions/counter1'
// 绑定action,自动派发事件给store
import {bindActionCreators} from '../redux'
let action = bindActionCreators(actions, store.dispatch)
export default class Counter extends React.Component {
state = store.getState().counter1
componentDidMount() {
store.subscribe(() => this.setState({
number: store.getState().counter1.number
}))
}
render () {
return (
<div>
<p>Counter: {this.state.number}</p>
{/* <button onClick={() => store.dispatch(actions.add())}>+</button>
<button onClick={() => store.dispatch(actions.minus())}>-</button> */}
{/* 自动配发事件的写法 */}
{/* <button onClick={action.add}>+</button>
<button onClick={action.minus }>-</button> */}
{/* 传参调用方式 */}
<button onClick={() => action.add1(1)}>+</button>
<button onClick={() => action.minus1(2)}>-</button>
</div>
)
}
}
根目录下index.js 的修改
import React from 'react';
import ReactDOM from 'react-dom';
import store from './store'
import Conuter from './components/Counter'
import Conuter2 from './components/Counter2'
import {Provider} from './react-redux'
ReactDOM.render(<Provider store={store}>
<Conuter />
<Conuter2 />
</Provider>, document.getElementById('root'));
总结
想了一下,不总接了,说了这么多,口有点干,手也有点酸
全部代码传送门