本文是一起学习造轮子系列的第三篇, 本篇我们将从零开始写一个 React-Redux, 本系列文章将会选取一些前端比较经典的轮子进行源码分析, 并且从零开始逐步实现, 本系列将会学习 Promises/A+,Redux,react-redux,vue,dom-diff,webpack,babel,kao,express,async/await,jquery,Lodash,requirejs,lib-flexible 等前端经典轮子的实现方式, 每一章源码都托管在 github 上, 欢迎关注~
相关系列文章:
一起学习造轮子(一): 从零开始写一个符合 Promises/A + 规范的 promise
一起学习造轮子(二): 从零开始写一个 Redux
一起学习造轮子(三): 从零开始写一个 React-Redux
本系列 github 仓库:
一起学习造轮子系列 github(欢迎 star~) https://github.com/JOE-XIE/MyWheel
前言
上一章我们写了一个 redux, 当 redux 与 react 结合时一般为了方便会使用 react-redux,
这个库是可以选用的. 实际项目中, 应该权衡一下, 是直接使用 Redux, 还是使用 React-Redux. 后者虽然提供了便利, 但是需要掌握额外的 API, 并且要遵守它的组件拆分规范.
- // 在根组件上将 userInfo 放入 context
- class Index extends Component {
- static childContextTypes = {
- userInfo: PropTypes.object
- }
- constructor() {
- super()
- this.state = {
- userInfo: {
- name:"小明",
- id:17
- }
- }
- }
- getChildContext() {
- return { userInfo: this.state.userInfo }
- }
- render() {
- return ( <div>
- <Header/>
- </div>
- )
- }
- }
- class Header extends Component {
- render() {
- return ( <div>
- <Title/>
- </div>
- )
- }
- }
- class Title extends Component {
- static contextTypes = {
- title: PropTypes.object
- }
- render() {
- // 无论组件层级有多深, 子组件都可以直接从 context 属性获取状态
- return ( <h1> 欢迎{ this.context.userInfo.name } </h1>)
- }
- }
- // root.js
- import { Provider } from 'react-redux'
- import { createStore } from 'redux'
- import userReducer from 'reducers/userReducer'
- import Header from 'containers/header'
- const store = createStore(userReducer)
- export default class Root extends Component {
- render() {
- return (<div>
- <Header></Header>
- </div>
- );
- };
- }
- ReactDOM.render( <Provider store = { store }>
- <Root/>
- </Provider>,
- document.getElementById('root'));
- //containers/header.js
- import { connect } from 'react-redux'
- import { bindActionCreators } from 'redux'
- import * as userinfoActions from 'actions/userinfo.js';
- import fetch from 'isomorphic-fetch'
- class Header extends Component {
- constructor() {
- super();
- this.state = {
- username:""
- }
- }
- componentDidMount(){
- this.getUserInfo()
- }
- getUserInfo(){
- fetch("/api/pay/getUserInfo")
- .then(response => {
- return response.json()
- })
- .then(json =>{
- this.props.userinfoActions.login(data);
- this.setState({username: data.username});
- })
- .catch(e => {
- console.log(e)
- })
- }
- render(){
- return (
- <div>
- </div>
- );
- }
- }
- function mapStateToProps(state) {
- return { userinfo: state.userinfo }
- }
- function mapDispatchToProps(dispatch) {
- return {
- userinfoActions: bindActionCreators(userinfoActions, dispatch)
- }
- }
- export default connect(mapStateToProps, mapDispatchToProps)(Header)
- // reducers/userReducer.js
- export default function userinfo(state = {}, action) {
- switch (action.type) {
- case "USERINFO_LOGIN":
- return action.data
- default:
- return state
- }
- }
- // actions/useraction.js
- export function login(data) {
- return {
- type: "USERINFO_LOGIN",
- data
- }
- }
- // Provider.js
- import React, { Component } from 'react';
- import propTypes from 'prop-types';
- export default class Provider extends Component {
- static childContextTypes = {
- store: propTypes.object.isRequired
- }
- getChildContext() {
- return { store: this.props.store };
- }
- render() {
- return this.props.children;
- }
- }
- import React, { Component } from 'react';
- import { bindActionCreators } from 'redux';
- import propTypes from 'prop-types';
- export default function connect(mapStateToProps, mapDispatchToProps) {
- return function(WrapedComponent) {
- // 壳组件
- class ProxyComponent extends Component {
- static contextTypes = {
- store: propTypes.object
- }
- constructor(props, context) {
- super(props, context);
- this.store = context.store;
- this.state = mapStateToProps(this.store.getState());
- }
- componentWillMount() {
- this.store.subscribe(() => {
- this.setState(mapStateToProps(this.store.getState()));
- });
- }
- render() {
- let actions = {};
- if (typeof mapDispatchToProps == 'function') {
- actions = mapDispatchToProps(this.store.disaptch);
- } else if (typeof mapDispatchToProps == 'object') {
- actions = bindActionCreators(mapDispatchToProps, this.store.dispatch);
- }
- // 壳组件内部渲染真正的组件实体, 并将业务组件想要的 store 里的状态及想要触发的 action 以 props 形式传入
- return <WrapedComponent {...this.state } {...actions}
- />
- }
- }
- return ProxyComponent;
- }
- }
- function mapDispatchToProps(dispatch) {
- return {
- userinfoActions: bindActionCreators(userinfoActions, dispatch)
- }
- }
- export default connect(mapStateToProps, mapDispatchToProps)(Header)
来源: https://www.cnblogs.com/XieJunBao/p/9284652.html