React搭建项目(全家桶)

  • 安装React脚手架:
    npm install -g create-react-app
  • 创建项目:
    create-react-app app

     app:为该项目名称

    或者跳过以上两步直接使用:

    npx create-react-app app

     

  • 启动项目:
    cd app
    npm start

项目创建完成,目录如下:

  • 安装 Ant Design:API Docs
    npm install antd --save
    或
    cnpm install antd
    --save
    cnpm i antd -S

    没有权限请使用 sudo

使用 babel-plugin-import(推荐)。

  1. 首先暴露配置文件:
    npm run eject

    NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting: https://reactjs.org/blog/2018/10/01/create-react-app-v2.html

    该操作为永久性,不可逆的。

  2. 在 package.json 中配置 babel (需要安装 babel-plugin-import 
    Error: Cannot find module 'babel-plugin-import'
    需要安装 babel-plugin-import
    npm install babel-plugin-import --save-dev
    或
    cnpm install babel-plugin-import --save-dev
    cnpm i babel-plugin-import -D

    babel 配置如下:

    "babel": {
        "presets": [
          "react-app"
        ],
        "plugins": [
          [
            "import",
            {
              "libraryName": "antd",
              "libraryDirectory": "es",
              "style": true
            }
          ]
        ]
    }

    使用 babel-plugin-import 的 style 配置来引入样式,需要将配置值从 'style': 'css' 改为 'style': true,这样会引入 less 文件。

  3. 配置 Ant Design 中文语言(默认文案是英文):配置文档

    在入口文件index.js中配置:
    import { ConfigProvider } from 'antd';
    import zh_CN from 'antd/lib/locale-provider/zh_CN';
    import moment from 'moment';
    import 'moment/locale/zh-cn';
    
    moment.locale('zh-cn');

    语言列表请参照:Ant Design 国际化

    另外需要使用 ConfigProvider 组件把 根组件 包裹起来:

    <ConfigProvider locale={zhCN}>
      <App />
    </ConfigProvider>

     

  • 安装配置 less 预处理器 && 配置 Ant Design 主题:  配置文档
    npm install less less-loader --save-dev

    cnpm install less less-loader --save-dev
    cnpm i less less-loader -D

    在 config/webpack.config.js 中配置 less:

    {
      test: /\.less$/,
      use: [
        {
          loader: 'style-loader',
        },
        {
          loader: 'css-loader', // translates CSS into CommonJS
        },
        {
          loader: 'less-loader', // compiles Less to CSS
          options: {
            lessOptions: { // If you are using less-loader@5 please spread the lessOptions to options directly
              modifyVars: {
                // 'primary-color': '#1DA57A',
                // 'link-color': '#1DA57A',
                // 'border-radius-base': '2px',
                // or
                // hack: `true; @import "your-less-file-path.less";`, // Override with less file
              },
              javascriptEnabled: true,
            },
          },
        },
      ],
    },

     

    配置位置如下:


    Ant Design 官网给出的可配置项:

  • @primary-color: #1890ff; // 全局主色
    @link-color: #1890ff; // 链接色
    @success-color: #52c41a; // 成功色
    @warning-color: #faad14; // 警告色
    @error-color: #f5222d; // 错误色
    @font-size-base: 14px; // 主字号
    @heading-color: rgba(0, 0, 0, 0.85); // 标题色
    @text-color: rgba(0, 0, 0, 0.65); // 主文本色
    @text-color-secondary : rgba(0, 0, 0, .45); // 次文本色
    @disabled-color : rgba(0, 0, 0, .25); // 失效色
    @border-radius-base: 4px; // 组件/浮层圆角
    @border-color-base: #d9d9d9; // 边框色
    @box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); // 浮层阴影

     

  • 安装 CSS resets: Normalize.css ( 样式重置 )
    npm install normalize.css --save

    cnpm install normalize.css --save
    cnpm i normalize.css -S
    安装完成后在入口文件index.js中引入即可。
    import 'normalize.css';
  • 安装配置 axios、qs : 
    npm install axios qs --save

    cnpm install axios qs --save
    cnpm i axios qs -S

     配置请求拦截器、响应拦截器:
     service.js:

    import axios from 'axios';
    
    const service = axios.create({
      // baseURL: window.location.origin,
      timeout: 30000,
      /*headers: {
        'Cache-Control': 'no-cache'
      }*/
    });

    /* 请求拦截器 */ service.interceptors.request.use((config) => { // 在这里配置请求 config
     return config; }, (err) => { console.error('请求发生了错误', err); return Promise.reject(err); }); /* 响应拦截器 */ service.interceptors.response.use((res) => { // 在这里配置响应拦截器 return res; }, (err) => { console.error('响应发生了错误', err); return Promise.reject(err); }); export default service;

    配置API调用方法:

    // 引入 axios 配置
    import service from './service';
    import qs from "qs";
    
    // post 请求
    export function apiPost(data = {}) {
      return service({
        url: "接口url",
        method: 'post',
        data: qs.stringify(data),
      });
    }
    
    // get 请求
    export function apiGet(params = {}) {
      return service({
        url: "接口url",
        method: 'get',
        params: params,
      });
    }

     

  • 配置跨域: Docs


    前面配置中 npm run eject 已经将配置暴露出来了
    npm install http-proxy-middleware --save
    或
    cnpm i http-proxy-middleware -S
    src 下新建 setupProxy.js
    const proxy = require('http-proxy-middleware');
    
    module.exports = function(app) {
      app.use(proxy('/api', { target: 'http://localhost:5000/' }));
    };

     

  • 安装配置路由 React-router:API Docs
    npm install react-router-dom --save
    或
    cnpm install react-router-dom --save
    cnpm i react-router-dom -S

     单独新建一个 router.js:或者在入口文件 index.js 中写路由视图)

    import React from 'react';
    import { BrowserRouter as Router, Route } from 'react-router-dom';
    import YourComponent from 'your-component-path';
    
    export default function () {
      return (
        <Router>
          <Route path='/' component={YourComponent} />
        </Router>
      );
    }

    然后在index.js里引用使用这个router.js:

    import Router from './path/router.js';
    
    export default function Index() {
      return <Router />;  
    }

    在哪个文件引用 router.js ,看个人项目构建喜好了,我是把 redux 和 antd 的配置 在 index.js 中引用的,把 router.js 在 app.js 中引用的,然后再把 app.js 引入到 index.js 中。
    可以看我 GitHub 的 mixins-demo

  • 安装配置 redux react-redux Docsredux Docs中文Docs
    npm install redux redux-thunk react-redux --save
    或
    cnpm install redux redux-thunk react-redux --save
    cnpm i redux redux-thunk react-redux -S

    在src目录下新建 redux 文件夹,作为配置 redux 的目录:

    actions: 针对不同功能模块进行配置的 actions 文件放在此目录
    reducers: 针对不同功能模块进行配置的 reducers 文件放在此目录
    reducers.js: 把所有reducers 结合起来
    store.js: 对 redux 的配置文件
    types.js: 存放Actions中所需要的 type 属性值

    各文件代码:
    types.js:

    export const MYTODO = 'MYTODO';
    export const MYLIST = 'MYLIST';
    export const OTHERTODO = 'OTHERTODO';
    export const OTHERLIST = 'OTHERLIST';

    myReducer.js:

    import { MYTODO, MYLIST } from '../types';
    const initState = {
      myTodos: [],
      list: [],
      // ...etc.
    };
    export default function (state = initState, action) {
      switch (action.type) {
        case MYTODO:
          return {
            ...state,
            myTodos: action.payload
          };
        case MYLIST:
          return {
            ...state,
            list: action.payload
          };
        default:
          return state;
      }
    }

    myActions.js:

    import { MYTODO, MYLIST } from "../types";
    
    export const myTodos = (params) => (dispatch, getState) => {
      // const { myState, otherState } = getState();
      dispatch({
        type: MYTODO,
        payload: params
      });
    };
    export const handleMyList = (params) => (dispatch, getState) => {
      // const { myState, otherState } = getState();
      dispatch({
        type: MYLIST,
        payload: params
      });
    };

    otherReducer.js:

    import { OTHERTODO, OTHERLIST } from '../types';
    const initState = {
      otherTodos: [],
      list: [],
      // ...etc.
    };
    export default function (state = initState, action) {
      switch (action.type) {
        case OTHERTODO:
          return {
            ...state,
            otherTodos: action.payload
          };
        case OTHERLIST:
          return {
            ...state,
            list: action.payload
          };
        default:
          return state;
      }
    }

    otherActions.js:

    import { OTHERTODO, OTHERLIST } from "../types";
    
    export const otherTodos = (params) => (dispatch, getState) => {
      // const { myState, otherState } = getState();
      dispatch({
        type: OTHERTODO,
        payload: params
      });
    };
    export const handleOtherList = (params) => (dispatch, getState) => {
      // const { myState, otherState } = getState();
      dispatch({
        type: OTHERLIST,
        payload: params
      });
    };

    reducers.js:

    import { combineReducers } from 'redux';
    import myReducer from './reducers/myReducer';
    import otherReducer from './reducers/otherReducer';
    
    export default combineReducers({
      myState: myReducer,
      otherState: otherReducer,
    });

    store.js:

    import { createStore, applyMiddleware, compose } from 'redux';
    import thunk from 'redux-thunk';
    import reducers from './reducers';
    
    const initState = {};
    const middleware = [thunk];
    
    const composeEnhancers =
      typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
        ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({})
        : compose;
    
    const enhancer =
      process.env.NODE_ENV === 'development'
        ? composeEnhancers(applyMiddleware(...middleware))
        : applyMiddleware(...middleware);
    
    export const store = createStore(reducers, initState, enhancer);

     

    以上Redux基本配置完成,下面是调用方法:

    import React, { useEffect } from 'react';
    import PropTypes from 'prop-types';
    import { connect } from 'react-redux';
    import { myTodos, handleMyList } from './path/redux/actions/myActions';
    
    function MyTodosComponent() {
      useEffect(() => {
        // 通过this.props 访问 state
        console.log(this.props.myTodos);
        console.log(this.props.list);
        // 调用 actions
        const todos = [
          {
            id: 1,
            todo: 'say hello world'
          }
        ];
        this.props.myTodos(todos);
        const list = [
          {
            id: 1,
            text: 'test',
          },
        ];
        this.props.handleMyList(list);
      }, []);
      return (
        <div>
          {
            this.props.todos.map((item, index) => {
              return (
                <div>id:{item.id}, todo:{item.todo}</div>
              );
            })
          }
        </div>
      );
    }
    // 类型检查
    MyTodosComponent.propTypes = {
      myTodos: PropTypes.array.isRequired,
      list: PropTypes.array.isRequired,
    };
    // 把redux中的state绑定到组件的props上
    const mapStateToProps = (state) => {
      const { myTodos, list } = state.myState;
      return {
        myTodos,
        list,
      };
    };
    // 把redux和组件结合起来,使组件能在props中访问到state和actions
    export default connect(
      mapStateToProps,
      {
        myTodos,
        handleMyList,
      },
    )(MyTodosComponent);

    以上代码只是示例,只需要关注配置和使用方法即可

    更多demo示例请看我的GitHub

posted @ 2019-06-04 20:11  果冻丨小布丁  阅读(689)  评论(0编辑  收藏  举报