使用React Hooks 16版本開發(fā)項目

前言: 本文僅展示部分基礎(chǔ)代碼料身,不涉及原理蜒滩。

一、 基本目錄樹

□ public (公共資源文件)
□ nav
□ sprite
- index.html
□ src (源代碼)
□ common (公共模塊)
□ components (組件/頁面)
□ routes (路由文件)
□ style (樣式)
□ utils (公共方法)
- App.js
- App.scss
- index.js (入口文件)

  • package.json
  • README.md

二弥姻、 入口文件示例

1. index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('pageWrapper'));

2. App.js

import React from 'react';
import './App.scss';
import { BrowserRouter } from 'react-router-dom';
import { Home } from './routes/Home';

function App() {
    return (
        <BrowserRouter>
            <Home />
        </BrowserRouter>
    );
}

export default App;

三婿禽、 路由文件示例

1. routes/Home.js

// 用戶登錄后的主界面入口模塊,界面結(jié)構(gòu)為:左側(cè)菜單欄+頂部導(dǎo)航條+內(nèi)容區(qū)域
function AppContainer() {
  // 通常使用現(xiàn)有的UI組件 配合 <Swtich>和<Route>組件
  // 例
    return (
    <Layout>
      <!-- 頂部導(dǎo)航 -->
      <Header>
        <NavMenu/>  
      </Header>
      <Body>
        <!-- 左側(cè)菜單 -->
        <Sider>
          <Menu>
            <Link to="/pathName">menuName</Link>
            ...
          </Menu>
        </Sider>
        <!-- 左側(cè)菜單路由配置 -->
        <Switch>
          <!-- 頁面 -->
          <Route path="/pathName" component={componentName}/>
          ... ...
          <!-- 內(nèi)部錯誤頁 -->
          <Route component={ErrorPage} /> 
        </Switch>
      </Body>
    </Layout>
  );
}

export default function Home() {
  return (
     <!-- 主路由配置巴席,包括登錄界面和登錄后跳轉(zhuǎn)的主界面 -->
    <Switch>
      <Redirect from="/" exact to="/home"></Redirect>
      <Route path="/login" component={Login} />
      <Route path="/home" component={AppContainer} />
      <!-- 系統(tǒng)錯誤頁 -->
      <Route component={ErrorPage} />
    </Switch>
  );
}

2. 路由對應(yīng)的 組件/頁面

  • components/Example/Index.js
import React from 'react';

export default function Example() {
    return (
        <div>我是組件內(nèi)容</div>
    )
};

四历涝、 axios請求示例

1. lib/axios.js 封裝axios方法

import Axios from 'axios';
import { request } from './request';

// axios 中間件注冊  文檔:https://github.com/axios/axios
const axiosInstance = Axios.create();

// 請求攔截示例
axiosInstance.interceptors.request.use(
    (config) => {
        let { url, data } = config;
        const headers = Object.assign({}, config.headers);
        // 統(tǒng)一請求網(wǎng)關(guān)接口
        url = "/gateway";
        // 請求頭添加公共參數(shù)
        Object.assign(headers, {
        "X-Common-Action": ActionName,
        "X-Common-Service": ServiceName,
        ... ...
        });
        data = JSON.stringify(data);

        Object.assign(config, {
          url,
          headers,
        });
        return config;
    }, function (error) {
        return Promise.reject(error)
    }
)

// 響應(yīng)攔截示例
axiosInstance.interceptors.response.use(
    res => {
        const { status, data } = res;
        
        if (status === 401) {
            window.location.href = '/login';
        }
        return res;
    }, error => {
        return Promise.reject(error);
    }
);

// 請求體添加公共參數(shù)
const mergeParams = (params) => {
  const commonParams = {
    Version: params.Version,
    Action: params.url,
    Service: params.name,
  };
  const proxyObj = {
    ...params.data,
  };
  return Object.assign(commonParams, proxyObj);
};

const axios = (config, params) => {
    const requestConfig = request(config);
    const { method, url, version } = requestConfig;
    return axios[method](url, mergeParams({ data: params, ...config }), {
      Version: version,
    });
};

// get請求 參數(shù)格式轉(zhuǎn)換 (轉(zhuǎn)換為 ?key=value&key=value 字符串)
function UrlDataFormat(param) {
  const keys = Object.keys(param);
  let requestBody = "";
  let requestobj = "";
  let requestend = "";
  let lastrequest = "";
  for (let i = 0; i < keys.length; i++) {
    if (typeof param[keys[i]] === "object") {
      const dd = param[keys[i]];
      const keyitems = Object.keys(dd);
      for (let k = 0; k < keyitems.length; k++) {
        if (typeof dd[keyitems[k]] === "object") {
          const keyon = Object.keys(dd[keyitems[k]]);
          for (let j = 0; j < keyon.length; j++) {
            if (typeof dd[keyitems[k]][keyon[j]] === "object") {
              const lastone = Object.keys(dd[keyitems[k]][keyon[j]]);
              for (let f = 0; f < lastone.length; f++) {
                lastrequest += `${keys[i]}.${keyitems[k]}.${keyon[j]}.${f}=${
                  dd[keyitems[k]][keyon[j]][f]
                }&`;
              }
            } else {
              requestend += `${keys[i]}.${keyitems[k]}.${keyon[j]}=${
                dd[keyitems[k]][keyon[j]]
              }&`;
            }
          }
        } else {
          requestobj += `${keys[i]}.${keyitems[k]}=${dd[keyitems[k]]}&`;
        }
      }
    } else {
      requestBody += `${keys[i]}=${param[keys[i]]}&`;
    }
  }
  return `?${requestBody}${requestobj}${requestend}${lastrequest}`;
}

axios.get = (url, params, config) =>
  axiosInstance({
    method: "get",
    url:
      url +
      UrlDataFormat({
        ...params,
      }),
    ...config,
  })
    .then((res) => {
      return Promise.resolve(res.data.Response);
    })
    .catch((err) => {
      return Promise.reject(err);
    });

axios.post = (url, params, config) => {
  return axiosInstance({
    method: "post",
    url,
    data: {
      ...params,
    },
    ...config,
  })
    .then((res) => {
      return Promise.resolve(res.data.Response);
    })
    .catch((err) => {
      return Promise.reject(err);
    });
};

export default axios;

2. lib/request.js (在axios.js文件里有調(diào)用request方法)

import apiName from './apiName';

export function request(serviceName) {
    const config = apiName[serviceName];
    return {
        url: `/${config.url}`,
        method: config.method,
        version: config.version,
    }
}

3. lib/apiName.js 配置接口列表

export default {
  Login: {
    method: "post",
    url: "/Login",
    version: "0.0.1",
  },
  ...
}

4. store/appApi.js 導(dǎo)出接口調(diào)用方法

import axios from "../lib/axios";

export function doLogin(data) {
  return axios({ name: "ServerName", url: "Login" }, data)
    .then((res) => Promise.resolve(res))
    .catch((err) => Promise.reject(err));
}

5. src/Login/Login.js 發(fā)起請求

import { doLogin } from '../../store/appApi';

doLogin(data).then(result => {
    if (!result.Response.Error) {
        history.push('/home'); // 登錄成功,跳轉(zhuǎn)到主界面
    }
})

五漾唉、 context狀態(tài)管理

1. context/appContext.js 定義context

import React from "react";

export const AppContext = React.createContext({
  LoginInfo: {},
  setLoginInfo: () => {},
});

2. src/Login/Login.js 使用

import React, { useContext } from "react";
import { AppContext } from "../../context/appContext";

const appContext = useContext(AppContext);

// 更新context狀態(tài)
appContext.setLoginInfo(Result);

// 獲取context狀態(tài)
console.log(appContext.LoginInfo);

六荧库、 props 父子組件數(shù)據(jù)傳遞

1. parent.js 父組件

import React, { useState } from 'react';
import Child from './child';  // 引入子組件

function Parent(){
    const [state, setState] = useState(0);  // 定義要傳遞的數(shù)據(jù)
    
    // 定義要傳遞的方法
    function parentFn(){
        // 做某事...
    }

    return (
        <!-- 使用子組件,綁定props -->
        <Child state={state} setState={setState} parentFn={parentFn}></Child>
    );
}

2. child.js 子組件

import React, { useEffect } from 'react';

function Child(props){
    
    useEffect(() => {
        console.log(props.state);  // 訪問父組件的state

        props.setState(1); // 修改父組件的state
    }, []);

    return (
        <button onClick={props.parentFn}>點擊我觸發(fā)父組件的parentFn方法</button>
    );
}

七赵刑、 常用 Hooks 新特性

1. useState

import React, { useState } from 'react';

function Example() {
    // ① 定義
    const [useName, setUseName] = useState("");
    const [age, setAge] = useState(0);
    const [list, setList] = useState([]);

    // ② 修改
    setUseName("小明");
    setAge(18);
    setList(['吃飯','睡覺']);

    return (
      <div>
        <!-- ③ 使用 -->
        <p>姓名: {useName}</p>
        <p>年齡: {age}</p>
        <p>愛好: </p>
        {list.map((item, index) => {
            return (
                <p key={index}>{item}</p>
            );
          })}
      </div>
    );
}

2. useEffect

import React, { useEffect } from "react";

function Example() {
    const [data, setData] = useState([]);
    const [params, setParams] = useState({});

    useEffect(() => {
        setData([]);
    }, []); // 參數(shù)[] 第一次渲染后分衫,僅調(diào)用一次。常用于動態(tài)請求數(shù)據(jù)渲染頁面般此。

    useEffect(() => {
        setData([]);
    }, [params]); // params參數(shù)每次改變時都觸發(fā)調(diào)用蚪战。
}

3. useRef

import React, { useRef } from 'react';

function Example() {
    const divEle = useRef(null);  // 定義

    useEffect(() => {
        console.log(divEle.current);  // 訪問
    }, []);

    return (
        <div ref={divEle}></div>  <!-- 綁定 -->
    );
}

4. useRouter

① 頁面跳轉(zhuǎn)

import React from 'react';
import useRouter from 'use-react-router';

function Example() {
    const { history } = useRouter();

    function goHome(){
        history.push('/home'); // 跳轉(zhuǎn)到首頁

        history.push('/home',{ Id: 1 }); // 跳轉(zhuǎn)到首頁铐懊,并傳參數(shù)
    }

    return (
        <button onClick={goHome}>回到首頁</button>
    );
}

② 獲取傳參

import React from 'react';
import useRouter from 'use-react-router';

function Example() {
    const { history } = useRouter();

    useEffect(() => {
        // 獲得傳遞過來的參數(shù)
        console.log(history.location.state);
        console.log(history.location.state.Id);
    }, [])

    return (
        <div>我是首頁</div>
    );
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邀桑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子科乎,更是在濱河造成了極大的恐慌壁畸,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喜喂,死亡現(xiàn)場離奇詭異瓤摧,居然都是意外死亡,警方通過查閱死者的電腦和手機玉吁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門照弥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人进副,你說我怎么就攤上這事这揣。” “怎么了影斑?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵给赞,是天一觀的道長。 經(jīng)常有香客問我矫户,道長片迅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任皆辽,我火速辦了婚禮柑蛇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘驱闷。我一直安慰自己耻台,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布空另。 她就那樣靜靜地躺著盆耽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扼菠。 梳的紋絲不亂的頭發(fā)上摄杂,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音循榆,去河邊找鬼匙姜。 笑死,一個胖子當著我的面吹牛冯痢,可吹牛的內(nèi)容都是我干的氮昧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼浦楣,長吁一口氣:“原來是場噩夢啊……” “哼袖肥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起振劳,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤椎组,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后历恐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寸癌,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡专筷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒸苇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磷蛹。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖溪烤,靈堂內(nèi)的尸體忽然破棺而出味咳,到底是詐尸還是另有隱情,我是刑警寧澤檬嘀,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布槽驶,位于F島的核電站,受9級特大地震影響鸳兽,放射性物質(zhì)發(fā)生泄漏掂铐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一揍异、第九天 我趴在偏房一處隱蔽的房頂上張望堡纬。 院中可真熱鬧,春花似錦蒿秦、人聲如沸烤镐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽炮叶。三九已至,卻和暖如春渡处,著一層夾襖步出監(jiān)牢的瞬間镜悉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工医瘫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侣肄,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓醇份,卻偏偏與公主長得像稼锅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子僚纷,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容