React-Redux:动手实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/b954960630/article/details/88169187

一、实现React-Redux的过程中的DOME样式

在这里插入图片描述
点击Blue变为:
在这里插入图片描述


二、概述及源码

1、组件设计

在这里插入图片描述

2、主要目录结构:
- public
	| - index.html
- src
	| -  index.js
	| - components
		| - react-redux.js 
		| - Contents.js
		| - Header.js
		| - ThemeSwitch.js
3、源码

注意:要先安装prop-types

(1)public文件夹下

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

(2)src文件夹下
index.js

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Header from './components/Header';
import Content from './components/Content';
import { Provider } from './components/react-redux';

//###############  redux核心函数  ############### 
function createStore (reducer) {
    let state = null;
    const listeners = [];
    const subscribe = (listener) => listeners.push(listener);
    const getState = () => state;
    const dispatch = (action) => {
        state = reducer(state, action);
        listeners.forEach((listener) => listener());
    }
    dispatch({}); // 初始化 state
    return { getState, dispatch, subscribe };
}

//############### 创建reducer、store ###############
const themeReducer = (state, action) => {
    if(!state) {
        return {
            themeColor: 'red'
        };
    } 
    switch(action.type) {
        case 'CHANGE_COLOR':
            return { ...state, themeColor: action.themeColor };
        default:
            return state;
    }
}
const store = createStore(themeReducer);

//#####################################################
class Index extends Component {
    render() {
        return (
            <div>
                <Header />
                <Content />
            </div>
        )
    }
}

ReactDOM.render(
    <Provider store={store}>
        <Index />
    </Provider>, 
    document.getElementById('root')
);

react.redux.js

import React, { Component } from 'react'
import PropTypes from 'prop-types'

//connect返回一个匿名函数,这个匿名函数就是高阶组件。
export const connect = (mapStateToProps, mapDispatchToProps) => 
    (WrappedComponent) => {
        class Connect extends Component {
            static contextTypes = {
                store: PropTypes.object,
            }

            constructor() {
                super();
                this.state = { allProps: {} };
            }
          
            componentWillMount() {
                const { store } = this.context;
                this._updateProps();
                store.subscribe(() => this._updateProps());
            }
          
            _updateProps () {
                const { store } = this.context;
                let stateProps = mapStateToProps
                    ? mapStateToProps(store.getState(), this.props)// 额外传入 props,让获取数据更加灵活方便
                    : {}; // 防止 mapStateToProps 没有传入
                let dispatchProps = mapDispatchToProps
                    ? mapDispatchToProps(store.dispatch, this.props)
                    : {};
                    
                this.setState({
                    allProps: { // 整合普通的 props 和从 state 生成的 props
                        ...stateProps,
                        ...dispatchProps,
                        ...this.props
                    }
                });
            }
          
            render () {
                return <WrappedComponent {...this.state.allProps} />
            }
        }
        return Connect;
    }
;

//Provider是一个容器组件; 它还会把外界传给它的 props.store 放到 context
export class Provider extends Component {
    static propTypes = {
        store: PropTypes.object,
        children: PropTypes.any
    }
  
    static childContextTypes = {
        store: PropTypes.object
    }
  
    getChildContext () { //把外界传进来的 props.store 放到 context
        return {
            store: this.props.store
        }
    }
  
    render () {
        return (
            <div>{this.props.children}</div>
        )
    }
}

Header.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from './react-redux';

class Header extends Component {
    static propTypes = {
        themeColor: PropTypes.string
    }; 
    render() {
        return (
            <h1 style={{ color: this.props.themeColor }}>React.js 小书</h1>
        );
    }
}

//告诉connect如何获取、整合状态
const mapStateToProps = (state) => {
    return {
        themeColor: state.themeColor
    }
};
Header = connect(mapStateToProps)(Header);
  
export default Header;

Content.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ThemeSwitch from './ThemeSwitch';
import { connect } from './react-redux';

class Content extends Component {
    static propTypes = {
        store: PropTypes.string,
    }

    render() {
        return (
            <div>
                <p style={{ color: this.props.themeColor }}>React.js 小书内容</p>
                <ThemeSwitch />
            </div>
        )
    }
}

//告诉connect如何获取、整合状态
const mapStateToProps = (state) => {
    return {
        themeColor: state.themeColor,
    }
};
Content = connect(mapStateToProps)(Content);

export default Content;

ThemeSwitch.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from './react-redux';

class ThemeSwitch extends Component {
    static propTypes = {
        themeColor: PropTypes.string,
        onSwitchColor: PropTypes.func
    }
    
    handleSwitchColor (color) {
        if (this.props.onSwitchColor) {
            this.props.onSwitchColor(color)
        }
    }

    render() {
        return (
            <div>
                <button 
                    style={{ color: this.props.themeColor }} 
                    onClick={() => this.handleSwitchColor('red')}>Red
                </button>
                <button 
                    style={{ color: this.props.themeColor }}
                    onClick={() => this.handleSwitchColor('blue')}>Blue
                </button>
            </div>
        )
    }
}

//告诉connect如何获取、整合状态
const mapStateToProps = (state) => {
    return {
        themeColor: state.themeColor
    }
};
//告诉connect如何触发 dispatch
const mapDispatchToProps = (dispatch) => {
    return {
        onSwitchColor: (color) => {
            dispatch({ type: 'CHANGE_COLOR', themeColor: color });
        },
    }
};

ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch);

export default ThemeSwitch;

猜你喜欢

转载自blog.csdn.net/b954960630/article/details/88169187