Webpack4+React16+ReactRouter4+Redux整合开发

{app.params.name}} {app.params.name}} {app.params.name}}

续接上文【Webpack4+React16+ReactRouter4整合开发

拉取github代码
https://github.com/durban89/webpack4-react16-reactrouter-demo.git

git clone https://github.com/durban89/webpack4-react16-reactrouter-demo.git webpack4-react16-reactrouter-redux
cd webpack4-react16-reactrouter-redux
npm install 
npm start

如果没有异常就可以正常写代码了

首先看下react-router-redux,从react-router官网的redux介绍部分可以看出写的是React Router Redux,但是点击后会告诉你Deprecated。我的天!废弃了,好吧,然后下面告诉你connected-react-router
我的天,又造了一个轮子,看来要重头学起了,没关系,咱们就是不怕折腾,人活着就是折腾嘛。
我们链接到connected-react-router,各种的炫耀夸,太多了,各种优点,我们还是来点实际的,操作开始

npm install redux react-redux history react-hot-loader connected-react-router --save

如何使用
修改src/index.jsx

1、第一步
添加第一部分 - 导入使用的库函数 

import { AppContainer } from 'react-hot-loader';
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { Provider } from 'react-redux';
import { connectRouter, ConnectedRouter, routerMiddleware } from 'connected-react-router';

添加第二部分 - 需要自己去定义

import rootReducer from './reducers'; // 这里的文件是新加的 - 具体是如何创建的可以看下项目代码
import routes from './routes'; // 这里的文件是新加的 - 具体是如何创建的可以看下项目代码

添加第三部分 - 配置redux相关的逻辑
 

const history = createBrowserHistory();
const initialState = {};
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  connectRouter(history)(rootReducer),
  initialState,
  composeEnhancer(applyMiddleware(routerMiddleware(history))),
);

添加第四部分 - 整合react-router

ReactDOM.render(
  (
    <AppContainer>
      <Provider store={store}>
        <ConnectedRouter history={history}>
          {routes}
        </ConnectedRouter>
      </Provider>
    </AppContainer>
  ),
  document.getElementById('root'),
);

最终src/index.jsx内容如下

import React from 'react';
import { AppContainer } from 'react-hot-loader';
import { createBrowserHistory } from 'history';
import { applyMiddleware, compose, createStore } from 'redux';
import { Provider } from 'react-redux';
import { connectRouter, ConnectedRouter, routerMiddleware } from 'connected-react-router';
import ReactDOM from 'react-dom';
import rootReducer from './reducers';
import routes from './routes';

const history = createBrowserHistory();
const initialState = {};
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  connectRouter(history)(rootReducer),
  initialState,
  composeEnhancer(applyMiddleware(routerMiddleware(history))),
);

ReactDOM.render(
  (
    <AppContainer>
      <Provider store={store}>
        <ConnectedRouter history={history}>
          {routes}
        </ConnectedRouter>
      </Provider>
    </AppContainer>
  ),
  document.getElementById('root'),
);

src/routes.jsx 主要配置路由跟组件的关系 -> 上面这行import routes from './routes';代码

import React from 'react';
import {
  BrowserRouter as Router,
  Route,
  Link as ALink,
} from 'react-router-dom';

import AppComponent from './components/AppComponent';
import HomeComponent from './components/HomeComponent';
import AboutComponent from './components/AboutComponent';
import TopicsComponent from './components/TopicsComponent';

const routes = (
  <div>
    <Router>
      <AppComponent>
        <ul>
          <li><ALink to="/">首页</ALink></li>
          <li><ALink to="/about">关于</ALink></li>
          <li><ALink to="/topics">论题</ALink></li>
        </ul>
        <hr />

        <Route exact path="/" component={HomeComponent} />
        <Route path="/about" component={AboutComponent} />
        <Route path="/topics" component={TopicsComponent} />
      </AppComponent>
    </Router>
  </div>
);

export default routes;

2、第二步
配置好了,就要开始使用了
1】、创建reducers
src/reducers/counter.js

const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
};

export default counterReducer;

2】、将counter.js加入到主reducers里面

src/reducers/index.js // 这里的文件就是对应这段代码 import rootReducer from './reducers';
import { combineReducers } from 'redux';
import counterReducer from './counter';

export default combineReducers({
  count: counterReducer,
});

3】、创建actions

src/actions/counter.js
export const increment = () => ({
  type: 'INCREMENT',
});

export const decrement = () => ({
  type: 'DECREMENT',
});

4】、添加一个组件src/components/CounterComponent.jsx

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

const {
  increment, decrement,
} = counter;

class CounterComponent extends Component {
  constructor(props, context) {
    super(props, context);

    this.state = {};
  }

  render() {
    const {
      count,
    } = this.props;

    return (
      <div>
        <p>数值: {count}</p>
        <button onClick={this.props.doIncrement}>+</button>
        <button onClick={this.props.doDecrement}>-</button>
      </div>
    );
  }
}

CounterComponent.propTypes = {
  count: PropTypes.number,
  doIncrement: PropTypes.func.isRequired,
  doDecrement: PropTypes.func.isRequired,
};

CounterComponent.defaultProps = {
  count: 0,
};

const mapStateToProps = state => ({
  count: state.count,
});

const mapDispatchToProps = dispatch => ({
  doIncrement: () => dispatch(increment()),
  doDecrement: () => dispatch(decrement()),
});


export default connect(mapStateToProps, mapDispatchToProps)(CounterComponent);

5】、将组件加到路由里面

src/routes.js

import React from 'react';
import {
  BrowserRouter as Router,
  Route,
  Link as ALink,
} from 'react-router-dom';

import AppComponent from './components/AppComponent';
import HomeComponent from './components/HomeComponent';
import AboutComponent from './components/AboutComponent';
import TopicsComponent from './components/TopicsComponent';
import CounterComponent from './components/CounterComponent';


const routes = (
  <div>
    <Router>
      <AppComponent>
        <ul>
          <li><ALink to="/">首页</ALink></li>
          <li><ALink to="/about">关于</ALink></li>
          <li><ALink to="/topics">论题</ALink></li>
          <li><ALink to="/counter">计数器</ALink></li>
        </ul>
        <hr />

        <Route exact path="/" component={HomeComponent} />
        <Route path="/about" component={AboutComponent} />
        <Route path="/topics" component={TopicsComponent} />
        <Route path="/counter" component={CounterComponent} />
      </AppComponent>
    </Router>
  </div>
);

export default routes;

6】、为了引入方便再加一个src/actions/index.js

import counter from './counter';

const actions = {
  counter,
};

export default actions;
export { counter };

到这里基本上就完工了,应该可以在页面看到计数器,并进行操作了

import { counter } from 'Actions';

这里是比较特殊的
这个要归功于webpack

resolve: {
    extensions: ['.js', '.jsx'], // 这里是必须要加的,不然默认的值加载['.js','.json']为后缀的文件
    alias: {
        Actions: path.resolve(__dirname, 'src/actions'),
    },
},

这里我们加了这个配置,于是在引入的时候就会正常引入需要的代码了。

好了,整个配置就完成了,项目我已经上传到github了,需要的同学可以自行去下载查看
 

实例项目地址:

https://github.com/durban89/webpack4-react16-reactrouter-demo.git
tag: v_1.0.1


版权声明

durban 创作并维护的 Gowhich 博客采用 创作共用保留署名-非商业-禁止演绎4.0国际许可证。

本文首发于 Gowhich 博客( https://www.gowhich.com ),版权所有,侵权必究。

本文永久链接: https://www.gowhich.com/blog/827

comments powered by Disqus