react深入 - 手写实现react-redux api
简介:简单实现react-redux基础api
react-redux api回顾
<Provider store>
把store放在context里,所有子组件可以直接拿到store数据
使组件层级中的 connect() 方法都能够获得 Redux store
根组件应该嵌套在 <Provider> 中
ReactDOM.render(
<Provider store={store}>
<MyRootComponent />
</Provider>,
rootEl
)
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<Route path="/" component={App}>
<Route path="foo" component={Foo}/>
<Route path="bar" component={Bar}/>
</Route>
</Router>
</Provider>,
document.getElementById('root')
)
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
链接组件和数据,把redux中的数据放到组件的属性中
[mapStateToProps(state, [ownProps]): stateProps] (Function)
如果定义该参数,组件将会监听 Redux store 的变化。任何时候,只要 Redux store 发生改变,mapStateToProps 函数就会被调用。该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并
如果你省略了这个参数,你的组件将不会监听 Redux store
ownProps,则该参数的值为传递到组件的 props,而且只要组件接收到新的 props,mapStateToProps 也会被调用,被重新计算
mapStateToProps 函数的第一个参数是整个Redux store的state,它返回一个要作为 props 传递的对象。它通常被称作 selector (选择器)。 可以使用reselect去有效地组合选择器和计算衍生数据.
注意:如果定义一个包含强制性参数函数(这个函数的长度为 1)时,ownProps 不会传到 mapStateToProps
const mapStateToProps = (state, ownProps) => {
return {
active: ownProps.filter === state.visibilityFilter
}
}
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function)
Object: 它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数(action creator),会被当作 Action creator ,返回的 Action 会由 Redux 自动发出,
Function: 会得到dispatch和ownProps(容器组件的props对象)两个参数(此时可能用到Redux 的辅助函数 bindActionCreators())
省略这个 mapDispatchToProps 参数,默认情况下,dispatch 会注入到你的组件 props 中,你可以this.props.dispatch调用
指定了该回调函数中第二个参数 ownProps,该参数的值为传递到组件的 props,而且只要组件接收到新 props,mapDispatchToProps 也会被调用
eg:
connect(mapStateToProps, {
hideAdPanel,
pushAdData,
})(AdPanel)
function mapDispatchToProps(dispatch) {
return {
todoActions: bindActionCreators(todoActionCreators, dispatch),
counterActions: bindActionCreators(counterActionCreators, dispatch)
}
}
知识点补充 - React高阶组件(Higher-Order Components)
高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件
高阶组件就是一个没有副作用的纯函数
使用场景:两个组件大部分代码都是重复的+且更好的封闭性,不需要关注数据的获取
import React, {Component} from 'react'
class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>welcome {this.state.username}</div>
)
}
}
export default Welcome;
import React, {Component} from 'react'
class Goodbye extends Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return (
<div>goodbye {this.state.username}</div>
)
}
}
export default Goodbye;
welcome和goodbye组件相似,只能获取的数据不一样,用高阶组件,提取公共部分
import React, {Component} from 'react'
export default (WrappedComponent) => {
class NewComponent extends Component {
constructor() {
super();
this.state = {
username: ''
}
}
componentWillMount() {
let username = localStorage.getItem('username');
this.setState({
username: username
})
}
render() {
return <WrappedComponent username={this.state.username}/>
}
}
return NewComponent
}
简化welcome和goodbye
import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
class Welcome extends Component {
render() {
return (
<div>welcome {this.props.username}</div>
)
}
}
Welcome = wrapWithUsername(Welcome);
export default Welcome;
此时,理解react-redux 的connect就好理解了
ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);
// connect是一个返回函数的函数(就是个高阶函数)
const enhance = connect(mapStateToProps, mapDispatchToProps);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store
// 关联起来的新组件
const ConnectedComment = enhance(Component);
provider实现
import React from 'react'
import ReactDOM from 'react-dom'
import { createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import { counter } from './index.redux'
// import { Provider } from 'react-redux'
// 换成自己的Provider实现
import { Provider } from './self-react-redux'
import App from './App'
const store = createStore(counter, compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
))
ReactDOM.render(
(
<Provider store={store}>
<App />
</Provider>
),
document.getElementById('root'))
./self-react-redux
import React from 'react'
import PropTypes from 'prop-types'
export function connect(){
}
class Provider extends React.Component{
static childContextTypes = {
store: PropTypes.object
}
getChildContext() {
return { store: this.store }
}
constructor(props, context) {
super(props, context)
this.store = props.store
}
render(){
return this.props.children
}
}
connect实现
demo
import React from 'react'
// import { connect } from 'react-redux'
import { connect } from './self-react-redux'
import { addGun, removeGun, addGunAsync } from './index.redux'
@connect(
// 你要state什么属性放到props里
state=>({num:state.counter}),
// 你要什么方法,放到props里,自动dispatch
{ addGun, removeGun, addGunAsync }
)
class App extends React.Component{
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>
)
}
}
export default App
./self-react-redux.js
// 高阶组件的写法
export function connect(maoStateToProps, mapStateToProps) {
return function(WrapComponent) {
return class ConnectComponent extends React.Component{
}
}
}
import React from 'react'
import PropTypes from 'prop-types'
import { bindActionCreator } from './self-redux'
// 使用简写形式
// connect负责链接组件,给到redux里的数据放在组件的属性里
// 1. 负责接收一个组件,把state里的一些数据放进去,返回一个组件
// 2. 数据变化的时候,能通知组件
export const connect = (
mapStateToProps = state => state,
mapDispatchToProps ={}
) => (WrapComponent) => {
return class ConnectComponent extends React.Component {
static contextTypes = {
store: PropTypes.object
}
constructor(props, context){
super(props, context)
this.state = {
props: {}
}
}
// 2 实现了mapStateToProps
componentDidMount() {
const { store } = this.context
store.subscribe(() => this.update())
this.update()
}
update() {
const { store } = this.context
// store.getState()这就是为什么mapStateToProps函数里面能拿到state
const stateProps = mapStateToProps(store.getState())
// 方法不能直接给,因为需要dispatch
/**
function addGun() {
return { type: ADD_GUN }
}
直接执行addGun() 毫无意义
要 addGun = () => store.dispatch(addGun()) 才有意义,其实就是把actionCreator包了一层
bindActionCreators在手写redux api实现了
*/
const dispatchProps = bindActionCreators(mapDispatchToProps, store.dispatch)
// 注意state的顺序问题会覆盖
this.setState({
props: {
...this.state.props,
...stateProps,
...dispatchProps,
}
})
}
// 1
render() {
return <WrapComponent {...this.state.props}></WrapComponent>
}
}
}
./self-redux.js
// creators: {addGun, removeGun, addGunAsync}
// creators[v]:addGun(参数)
// 返回:(参数) => dispatch(addGun(参数))
function bindActionCreator(creator, dispatch) {
return (...args) => dispatch(creator(...args))
}
export function bindActionCreators(creators, dispatch) {
let bound = {}
Object.keys(creators).forEach( v => {
let creator = creators[v]
bound[v] = bindActionCreator(creator, dispatch)
})
return bound
}
// 简写
export function bindActionCreators(creators, dispatch) {
return Object.keys(creators).reduce((ret, item) => {
ret[item] = bindActionCreator(creators[item], dispatch)
return ret
}, {})
}
原文地址:https://segmentfault.com/a/1190000016759675
react深入 - 手写实现react-redux api的更多相关文章
- React深入 - 手写redux api
简介: 手写实现redux基础api createStore( )和store相关方法 api回顾: createStore(reducer, [preloadedState], enhancer) ...
- react纯手写全选与取消全选
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 手写一个json格式化 api
最近写的一个东西需要对json字符串进行格式化然后显示在网页上面. 我就想去网上找找有没有这样的api可以直接调用.百度 json api ,搜索结果都是那种只能在网页上进行校验的工具,没有api. ...
- 手写一个React-Redux,玩转React的Context API
上一篇文章我们手写了一个Redux,但是单纯的Redux只是一个状态机,是没有UI呈现的,所以一般我们使用的时候都会配合一个UI库,比如在React中使用Redux就会用到React-Redux这个库 ...
- 放弃antd table,基于React手写一个虚拟滚动的表格
缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...
- 手写React的Fiber架构,深入理解其原理
熟悉React的朋友都知道,React支持jsx语法,我们可以直接将HTML代码写到JS中间,然后渲染到页面上,我们写的HTML如果有更新的话,React还有虚拟DOM的对比,只更新变化的部分,而不重 ...
- 手写系列-实现一个铂金段位的 React
一.前言 本文基于 https://pomb.us/build-your-own-react/ 实现简单版 React. 本文学习思路来自 卡颂-b站-React源码,你在第几层. 模拟的版本为 Re ...
- 手写一个Redux,深入理解其原理
Redux可是一个大名鼎鼎的库,很多地方都在用,我也用了几年了,今天这篇文章就是自己来实现一个Redux,以便于深入理解他的原理.我们还是老套路,从基本的用法入手,然后自己实现一个Redux来替代源码 ...
- 手写 redux 和 react-redux
1.手写 redux redux.js /** * 手写 redux */ export function createStore(reducer) { // 当前状态 let currentStat ...
随机推荐
- 纯JS实现元素加速运动的函数封装
//elem:给哪个元素添加位移:direction:是垂直方向的话就传入top,水平方向left:speed控制速度,向下.向右传入正值,反之传入负值:distance表示位移的距离function ...
- Luogu P2170选学霸【并查集+背包】By cellur925
题目传送门 开始看到本题完全认为就是个彻头彻尾的并查集,只要把实力相当的人都并到一个集合中,最后再找一共有多少联通块即可. 后来发现这是大错特错的qwq.因为选了一个集合中的某人,那这个集合中所有人就 ...
- 进程动态拦截注入API HOOK
最近工作中遇到一个问题,需要通过程序界面进行判断程序的运行状态,刚开始认为很简单,不就是一个窗体控件获取,获取Button的状态和Text.刚好去年干过该事情,就没太在意,就把优先级排到后面了,随着项 ...
- ssh公私密钥的生成
ssh密钥的生成 root账号密钥的生成: 这里我们切换到root账号下,执行ssh-keygen命令: ssh-keygen -t dsa 然后一路回车即可 """ [ ...
- AtCoder Grand Contest 001 D - Arrays and Palindrome
题目传送门:https://agc001.contest.atcoder.jp/tasks/agc001_d 题目大意: 现要求你构造两个序列\(a,b\),满足: \(a\)序列中数字总和为\(N\ ...
- Xcode7.1环境下上架iOS App到AppStore 流程 转
来自:http://www.cnblogs.com/ChinaKingKong/p/4957682.html 前言部分 之前App要上架遇到些问题到网上搜上架教程发现都是一些老的版本的教程 ,目前iT ...
- 看Facebook是如何优化React Native性能
原文出处: facebook 译文出处:@Siva海浪高 该文章翻译自Facebook官方博客,传送门 React Native 允许我们运用 React 和 Relay 提供的声明式的编程模型, ...
- [转]如何使用MFC和类型库创建自动化项目
本文转自:http://www.cnblogs.com/zhoug2020/archive/2012/04/01/2429064.html 摘要 本文详细介绍了如何自动化像Microsoft Offi ...
- Mysql框架---HMySql
Java 数据库框架 在我学习java数据库框架的时候,第一个用的是Hibernate,但是到现在,我可能已经快忘记它了,毕竟快两年没有碰的东西,后来一直再用MyBatis.因为它简单. 但是本文不会 ...
- 2019/05/13 JAVA虚拟机堆内存调优
-Xms4000m 堆内存初始值 * -Xmx4000m 堆内存最大值 * -XX:+PrintGCDetails 打印GC信息 * -XX:+UseSerialGC 使用串行GC * -XX:+Pr ...