從零開始react實戰:雲書籤-1 react環境搭建

  • 2019 年 10 月 3 日
  • 筆記

????react ??????

??????

????????????????? react ????,?create-react-app???????????

  • antd ??????? ???????
  • ?? less ?????? css-module
  • ????
  • ?? http ??
  • ?? redux

??:?? node ???? 8.0.

?? create-react-app

  1. ??
npm install -g create-react-app
  1. ?? react ??
create-react-app bookmark-world

?????????????

????

?? antd,less

????????????????

  • ??npm run eject?????????? ???????????????????????????.
  • ??react-app-rewired????.

??????????????–?????

??????

? 2.1.x ??? react-app-rewired ????customize-cra???????????????????

  • react-app-rewired ,????
  • customize-cra ,????
  • antd ,ui ?
  • babel-plugin-import ,???? antd
  • less ,less ??
  • less-loader ,less ??

?????

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

?? package.json

?react-app-rewired??????react-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",  }

?? config-overrides.js

??????,???package.json???????config-overrides.js??.?????

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" }    })  );

?? css-module

??? css-module ??? css ?????fileName.module.less?????????????????????

????????????.module.less ??? 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;

????

???? src ????????????

????

?????

  • assets: ?????????????
  • components???????
  • layout: ??????????????????????
  • pages: ??????
  • redux??? redux ??
    • action: ?? action
    • reducer: ?? reducer ??
  • util: ???

??serviceWorker.js?????index.js???????????????????????

????react-router??:

cnpm install --save react-router-dom

?????????? react ???? js ????react-router-dom ??????????????????????history???

????index.js?????<BrowserRouter>????? history ????????

// 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"));

??????????????????????????????? App.jsx ?????????(????????????????????????)

???????????????????

  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>    );  }

?????

  • Switch: ???????????????????????
  • Route?????
  • exact???????????????/???/,?????????
  • Redirect????????????????????????????exact? path ?/),??????/404

??????????????????????

?? http ????

http ??????????axios?

???????

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. ????????pages/public/Login/index.js
    ????????
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);

??????????????

  • mapStateToProps:?????? store ???????????? Login ??? props ??
  • mapDispatchToProps:??????? store ??????????????? Login ??? props ?,??? dispath ??????? reducer ????????? changeLoginInfo ??? action?
  • connect ???????????? Login ???????????? props ?????????? withRouter,?? withRouter ??????

?????????? yapi ? mock ??????????????????

??

????????? react ???????????????

???github,??? tag:???????????????????????

????????www.tapme.top/blog/detail/20190626