前言: 本文僅展示部分基礎(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>
);
}