Scratch react combat: Bookmark -1 react cloud environment to build

Overview chapter: REACT combat Cloud Bookmarks

Benpian is the first real series, mainly to build react development environment, in create-react-appplus the following functions on the basis of:

  • antd component libraries needed to introduce, support custom theme
  • Support less grammar, and use css-module
  • Configuring Routing
  • Support http request
  • Configuration redux

Note : Requires node version greater than 8.0.

Create a create-react-app

  1. installation
npm install -g create-react-app
  1. Creating react Application
create-react-app bookmark-world

Generating a directory structure as shown below:

Directory Structure

Configuring antd, less

There are two ways to edit its configuration:

  • By npm run ejectexposing the configuration file, and then modify the configuration files, the following method is not compared to the elegant, and therefore not considered.
  • By react-app-rewiredcovering configuration.

Subsequent configuration changes are required with a second - coverage configuration.

First install dependencies

In the 2.1.x version of the react-app-rewired with the need customize-crato be configured to cover. Need to install the following dependency:

  • react-app-rewired, arranged to cover
  • customize-cra, arranged to cover
  • antd, ui library
  • babel-plugin-import, demand introduction antd
  • less, less support
  • less-loader, less support

code show as below:

npm install --save react-app-rewired customize-cra antd babel-plugin-import less less-loader

Modify package.json

With react-app-rewiredout the original replacementreact-scripts

/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test",
+   "test": "react-app-rewired test",
}

Create a config-overrides.js

In the project root directory, which is package.jsonin the same directory create config-overrides.jsa file as follows:

const { override, fixBabelImports, addLessLoader } = require("customize-cra");

module.exports = override(
  fixBabelImports("import", {
    libraryName: "antd",
    libraryDirectory: "es",
    style: true
  }),
  addLessLoader({
    localIdentName: "[local]--[hash:base64:5]",
    javascriptEnabled: true,
    modifyVars: { "@primary-color": "#1DA57A" }
  })
);

Use css-module

To use css-module needs to css file name fileName.module.less, and then can be introduced in normal use of the assembly, as follows:

Note that the default file the case must be .module.less to use the wording of the css-module

import React, { Component } from "react";
import { Button } from "antd";
import styles1 from "./index.module.less";

class Hello extends Component {
  render() {
    return (
      <div className={styles1.main}>
        hello
        <div className={styles1.text}>world</div>
        <Button type="primary">你好</Button>
        <div className="text1">heihei</div>
      </div>
    );
  }
}

export default Hello;

Configuring Routing

First modify the src directory structure. Changed as follows:

Directory Structure

Catalog explained:

  • assets: storage icons, small pictures and other resource files
  • components: storage of common components
  • layout: pattern storage component for nesting and routing code reuse neutral Zi
  • pages: store page components
  • redux: redux related storage
    • action: store action
    • reducer: reducer storage operations
  • util: Tools

Delete serviceWorker.jsfiles, and index.jsdelete the code associated with it. This is related to the use and offline.

Then install react-routerdepend on:

cnpm install --save react-router-dom

From the beginning of the route will be able to understand the essence of js react everything, react-router-dom provide some routing component to route operations. This program uses historyrouting.

First modify the index.jsroot component placed <BrowserRouter>next to open the route history. code show as below:

// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";

const s = (
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

ReactDOM.render(s, document.getElementById("root"));

Then there are many ways to configure the route, here by way hoc routing code, and a routing configuration will App.jsx center. (Also based on the configuration file, and then write a code configuration file parsing)

Log in to join Home and routing, the main code is as follows:


render() {
  const mainStyle = {
    fontSize: "0.16rem"
  };
  return (
    <Provider store={store}>
      <div className="fullScreen" style={mainStyle}>
        <Switch>
          <Route exact path="/" component={Main} />
          <Route exact path="/public/login" component={Login} />
          <Route exact path="/404" component={NotFound} />
          {/* 当前面的路由都匹配不到时就会重定向到/404 */}
          <Redirect path="/" to="/404" />
        </Switch>
      </div>
    </Provider>
  );
}

Glossary:

  • Switch: This component represents only one match, a match is not continue to match down
  • Route: Routing Component
  • exact: represents the exact match, if this is turned on, /only the match /, otherwise all paths match
  • Redirect: Redirect component does not match the current surface will match this (because there is no open exactand the path is /), then redirect to/404

It will be more in-depth explanation of routing related subsequent use nested routes.

Configure the http request tool

http request tool selection here is axios.

First Installation depends:

cnpm install --save axios

然后编写工具类util/httpUtil.js,代码如下:

// httpUtil.js

import { notification } from "antd";
import axios from "axios";

//定义http实例
const instance = axios.create({
  //   baseURL: "http://ali.tapme.top:8081/mock/16/chat/api/",
  headers: {
    token: window.token
  }
});

//实例添加拦截器
instance.interceptors.response.use(
  function(res) {
    return res.data;
  },
  function(error) {
    console.log(error);
    let message, description;
    if (error.response === undefined) {
      message = "出问题啦";
      description = "你的网络有问题";
    } else {
      message = "出问题啦:" + error.response.status;
      description = JSON.stringify(error.response.data);
      //401跳转到登录页面
    }
    notification.open({
      message,
      description,
      duration: 2
    });
    setTimeout(() => {
      if (error.response && error.response.status === 401) {
        let redirect = encodeURIComponent(window.location.pathname + window.location.search);
        window.location.replace("/public/login?redirect=" + redirect);
      }
    }, 1000);
    return Promise.reject(error);
  }
);

export default instance;

主要实现了如下功能:

  • 自动添加 token,设计前后端通过 jwt 做认证,因此每个请求都要加上 token
  • 响应预处理,如果有错误,自动弹窗提示。如果响应码为 401,重定向到登录页面。

配置 redux

redux 算是 react 的一大难点。这里我们可以把 redux 理解成一个内存数据库,用一个对象来存储所有的数据.

对这个数据的修改有着严格的限制,必须通过 reducer 来修改数据,通过 action 定义修改的动作。

这里以用户登录数据为例。

定义

  1. 首先定义 action,创建文件redux/action/loginInfoAction.js,代码如下:
// 定义登录信息在store中的名字
export const DATA_NAME = "loginInfo";

//定义修改loginInfo type
export const CHANGE_LOGIN_INFO = "changeLoginStatus";

export const changeLoginInfo = (token, userInfo) => {
  return {
    type: CHANGE_LOGIN_INFO,
    data: {
      token,
      userInfo
    }
  };
};
  • CHANGE_LOGIN_INFO :定义操作类别
  • changeLoginInfo: 定义一个 action,在组件中调用,传入要修改的数据,在这里加上 type 上传递到 reducer 中处理.
  1. 定义 reducer,创建文件redux/reducer/loginInfo.js,代码如下:
import * as loginAction from "../action/loginInfoAction";

function getInitData() {
  let token, userInfo;
  try {
    token = localStorage.getItem("token");
    userInfo = JSON.parse(localStorage.getItem("userInfo"));
  } catch (e) {
    console.error(e);
    token = null;
    userInfo = null;
  }
  window.token = token;
  window.userInfo = userInfo;
  return {
    token,
    userInfo
  };
}

const LoginStatusReducer = (state = getInitData(), action) => {
  switch (action.type) {
    case loginAction.CHANGE_LOGIN_INFO:
      return { ...action.data };
    default:
      return state;
  }
};

export default LoginStatusReducer;
  • getInitData 方法用于初始化 userInfo 数据,这里写的比较复杂,会先从 localeStore 中取数据,然后挂载到 window 中,方便httpUtil中获取 token。
  • LoginStatusReducer 方法用于处理 action 中的数据,输出处理后的 loginInfo 数据。
  1. 编写 reducer 汇总类(redux/reducer/index.js),所有 reducer 都要汇总到一个方法中,这样就能生成整个系统的 store 对象。代码如下:
import { combineReducers } from "redux";
import { DATA_NAME } from "../action/loginInfoAction";
import loginInfo from "./loginInfo";

const data = {};
data[DATA_NAME] = loginInfo;

const reducer = combineReducers(data);

export default reducer;
  1. 编写redux/index.js,这里生成真正的数据对象,代码如下:
import { createStore } from "redux";
import reducer from "./reducer";

const store = createStore(reducer);

export default store;
  1. 最后将 store 绑定到根节点(App.js)中即可,修改部分如下:

使用

这里以登录页为例,学习如何获取到 loginInfo 和修改 loginInfo.

  1. Components to create a login page, pages/public/Login/index.js
    login page code is as follows:
import React, { Component } from "react";
import queryString from "query-string";
import { Button, Input, message } from "antd";
import IconFont from "../../../components/IconFont";
import styles from "./index.module.less";
import { connect } from "react-redux";
import { changeLoginInfo, DATA_NAME } from "../../../redux/action/loginInfoAction";
import axios from "../../../util/httpUtil";

function mapStateToProps(state) {
  return state[DATA_NAME];
}

function mapDispatchToProps(dispatch) {
  return {
    updateLoginInfo: (token, userInfo) => dispatch(changeLoginInfo(token, userInfo))
  };
}

class Login extends Component {
  constructor(props) {
    super(props);
    this.state = {
      username: "",
      password: ""
    };
    this.query = queryString.parse(window.location.search);
  }

  usernameInput = e => {
    this.setState({ username: e.target.value });
  };
  passwordInput = e => {
    this.setState({ password: e.target.value });
  };

  submit = () => {
    axios.post("/public/login", this.state).then(res => {
      localStorage.setItem("token", res.token);
      localStorage.setItem("userInfo", JSON.stringify(res.userInfo));
      window.token = res.token;
      window.userInfo = res.userInfo;
      message.success("登录成功");
      this.props.updateLoginInfo(res.token, res.userInfo);
      if (this.query.redirect) {
        this.props.history.replace(decodeURIComponent(this.query.redirect));
      } else {
        this.props.history.replace("/");
      }
    });
  };

  render() {
    return (
      <div className="fullScreen flex main-center across-center">
        // 省略其他部分
        <Button type="primary" onClick={this.submit}>
          登录
        </Button>
        ...
      </div>
    );
  }
}

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

One of the most critical is the following three parts:

  • mapStateToProps: This method requires acquiring data from the entire store, the delivery to the props Login assembly.
  • mapDispatchToProps: This method is used to modify the data store, the function also returns the object bound to the props Login assembly, dispath the parameters for processing the function call in the reducer, according action changeLoginInfo returned.
  • The above method is used to connect two components bind Login and functions, so that the props can be obtained in a. If there is withRouter , should withRouter on the outermost layer.

Interface login access is currently yapi the mock data, the real background code will be written later.

end

As a rookie just starting to learn react, to welcome you, Daniel criticism.

Source: GitHub , switch to Tag: 第一篇:环境搭建, we can see that as of Benpian source.

Original article published on: www.tapme.top/blog/detail/20190626

Guess you like

Origin www.cnblogs.com/wuyoucao/p/11273965.html