目錄
一枫耳、前言
二即舌、通信
三辨宠、生命周期
四饥漫、基礎(chǔ)api的使用
六薛窥、react-redux
六噩凹、其他
</details>
前言
環(huán)境
"react": "^17.0.2" "redux": "^4.1.2"
REACT17版本的新變化
雖然沒(méi)有新功能孤个, 但具有戰(zhàn)略意義;
事件委托機(jī)制改變
向原生瀏覽器靠攏
useEffect清理操作改為異步操作沛简;
JSX不可返回undefined
總結(jié):沒(méi)有新功能齐鲤,允許多版本混用,逐步升級(jí)。
通信
父子組件傳遞props
父組件
<Robot id="{123}" name="路線評(píng)價(jià)" email="height@163.com"/>
子組件
// 定義接口
interface RobotProps {
id: number;
name: string;
email: string;
}
// 直接解構(gòu)使用
const Robot: React.FC<RobotProps> = ({ id, name, email }) => {
return (
<div className={styles.cardContainer}>
<img alt="robot" src={`https://robohash.org/${id}`}></img>
<h2>{name}</h2>
<p>{email}</p>
</div>
)
}
export default Robot;
生命周期
Mounting:創(chuàng)建虛擬DOM椒楣, 渲染UI
Updating: 更新虛擬DOM给郊, 重新渲染UI
Unmounting 刪除虛擬DOM, 移除UI
初始化 => 更新 => 銷毀
基礎(chǔ)api的使用
hooks
hooks的本質(zhì)是一類特殊的函數(shù)捧灰,為你的函數(shù)型式組件注入特殊的功能; hooks的目的是給函數(shù)式組件加上狀態(tài)淆九;
常見(jiàn)的鉤子函數(shù):
- useState
- useEffect
- useContext
useState
useState常見(jiàn)用法
import { useState } from "react";
xport const FilterTag: React.FC<PropsType> = (props) => {
const [loading, setLoading] = useState<boolean>(false)
setLoading(true)
if (loading) {
return (
<Spin
size="large"
style={{
marginTop: 200,
marginBottom: 200,
marginLeft: "auto",
marginRight: "auto",
width: "100%",
}}
/>
);
}
};
useEffect
輸入?yún)?shù)一樣,輸出結(jié)果不一樣的情況毛俏。就是副作用炭庙。
比如:
Ajax,修改DOM,甚至是console.log煌寇;
REACT: state的狀態(tài)改變焕蹄, 生命周期,構(gòu)建函數(shù)阀溶;
副作用會(huì)給系統(tǒng)添加不可控的因素腻脏,但是不要害怕。
useEffect常見(jiàn)用法
// 1. 每次UI渲染银锻,都會(huì)觸發(fā)
useEffect(() => {
console.log('useEffect')
})
// 2. 相當(dāng)于生命周期 componentDidMount永品,是 DOM掛載后,只執(zhí)行一次
// 使用場(chǎng)景:多數(shù)用在 fetch數(shù)據(jù) 的時(shí)候
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => {
return response.json()
})
.then((data) => setRobotGallery(data))
}, [])
// 3. 相當(dāng)于watch監(jiān)聽(tīng)器
useEffect(() => {
console.log('useEffect')
document.title = `點(diǎn)擊${count}次`
}, [count])
useContext
爺孫組件通信
以前: context Provider 和 Consumer
現(xiàn)在:context Provide 和useContext
作用:類似于一個(gè)統(tǒng)一的狀態(tài)管理徒仓。后面可以用react-redux
代替腐碱;
// 爺組件 index.tsx
const defaultContextValue = {
userName: 'height'
}
export const appContext = React.createContext(defaultContextValue)
ReactDOM.render(
<React.StrictMode>
<appContext.Provider value={defaultContextValue}>
<App />
</appContext.Provider>
</React.StrictMode>,
document.getElementById('root')
);
// 孫組件 Robot.tsx
import React, {useContext} from 'react'
import { appContext } from "../index";
const Robot: React.FC<RobotProps> = () => {
const value = useContext(appContext);
return (
<!-- 輸出:height -->
<p>作者:{value.userName}</p>
)
}
上面代碼優(yōu)化一下,將provider組件化
// AppState.tsx 文件
// props.children即子組件
import React, { useState } from 'react'
interface AppStateValue {
username: string;
shoppingCart: { items: {id: number, name: string}[]}
}
const defaultContextValue : AppStateValue = {
username: 'heightzhang',
shoppingCart: { items: []}
}
export const appContext = React.createContext(defaultContextValue)
export const AppStateProvider:React.FC = (props) => {
const [state, setState] = useState(defaultContextValue)
return (
<appContext.Provider value={state}>
{props.children}
</appContext.Provider>
)
}
// index.tsx文件
import { AppStateProvider } from './AppState'
ReactDOM.render(
<React.StrictMode>
<AppStateProvider>
<App />
</AppStateProvider>
</React.StrictMode>,
document.getElementById('root')
);
自定義Hook
- Hook是函數(shù)
- 命名以"use"開(kāi)頭
- 內(nèi)部可調(diào)用其他Hook函數(shù)
- 并非React的特性
// 使用自定義hooks useAddToCart
import React, { useContext } from 'react'
import styles from './Robot.module.css'
import { appContext, appSetStateContext } from "../AppState";
import { useAddToCart } from './AddToCart'
interface RobotProps {
id: number;
name: string;
email: string;
}
const RobotDicount: React.FC<RobotProps> = ({ id, name, email }) => {
const value = useContext(appContext);
const setState = useContext(appSetStateContext)
const addToCart = useAddToCart()
return (
<div className={styles.cardContainer}>
<img alt="robot" src={`https://robohash.org/${id}`}></img>
<h2>打折商品</h2>
<h2>{name}</h2>
<p>{email}</p>
<p>作者:{value.username}</p>
<button onClick={() => addToCart(id, name)}>加入購(gòu)物車</button>
</div>
)
}
export default RobotDicount;
// 定義自定義hooks 導(dǎo)出一個(gè)函數(shù)
export const useAddToCart = () => {
const setState = useContext(appSetStateContext)
const addToCart = (id, name) => {
if (setState) {
setState((state) => {
return {
...state,
shoppingCart: {
items: [...state.shoppingCart.items, { id, name }],
},
};
});
}
}
return addToCart
}
高階組件HOC
高階組件(HOC)是Ract中用于復(fù)用組件邏輯的一種高級(jí)技巧掉弛。HOC自身不
是React API的一部分,它是一種基于React的組合特性而形成的設(shè)計(jì)模式喂走。
具體而言殃饿,高階組件是參數(shù)為組件,返回值為新組件的函數(shù)芋肠。
為什么要使用高階組件乎芳?
- 抽取重復(fù)代碼,實(shí)現(xiàn)組件復(fù)用
- 條件渲染,控制渲染組件的渲染邏輯(渲染劫持)
- 捕獲/劫持被處理組件的生命周期
// HOC組件 一般使用with開(kāi)頭奈惑, withXXX() => withAddToCart()
// 使用 公共方法 addToCart
import React, {useContext} from 'react'
import styles from './Robot.module.css'
import { appContext, appSetStateContext } from "../AppState";
import {withAddToCart} from './AddToCart'
export interface RobotProps {
id: number;
name: string;
email: string;
addToCart: (id, name) => void;
}
const Robot: React.FC<RobotProps> = ({ id, name, email, addToCart }) => {
const value = useContext(appContext);
const setState = useContext(appSetStateContext)
return (
<div className={styles.cardContainer}>
<img alt="robot" src={`https://robohash.org/${id}`}></img>
<h2>{name}</h2>
<p>{email}</p>
<p>作者:{value.username}</p>
<button onClick={() => addToCart(id, name)}>加入購(gòu)物車</button>
</div>
)
}
export default withAddToCart(Robot);
// withAddToCart.tsx
import React, { useContext } from "react";
import { appSetStateContext } from "../AppState";
import { RobotProps } from "./Robot";
export const withAddToCart = (ChildComponent: React.ComponentType<RobotProps>) => {
return (props) => {
const setState = useContext(appSetStateContext)
const addToCart = (id, name) => {
if (setState) {
setState((state) => {
return {
...state,
shoppingCart: {
items: [...state.shoppingCart.items, { id, name }],
},
};
});
}
}
return <ChildComponent {...props} addToCart={addToCart} />
}
}
對(duì)比hook和HOC
需要生命周期的時(shí)候用HOC吭净,只是單純的公共函數(shù)方法用hook。
react-router
路由跳轉(zhuǎn)
1.push
import { useHistory } from "react-router-dom";
const history = useHistory();
history.push()
2.replace
import { useHistory } from "react-router-dom";
const history = useHistory();
history.replace()
3.back
import { useHistory } from "react-router-dom";
const history = useHistory();
history.goBack()
攜帶參數(shù)
1.query
// 配置路由 router.tsx 配置路由頁(yè)面
<Route path="/detail/:touristRouteId" component={DetailPage}></Route>
// 跳轉(zhuǎn)路由 productList.tsx頁(yè)面
history.push(`detail/${id}`)
// 獲取參數(shù) deatail.tsx頁(yè)面
import { RouteComponentProps, useParams } from 'react-router-dom'
interface MatchParams {
touristRouteId: string
}
let { touristRouteId } = useParams<MatchParams>()
2.params
路由攔截/私有路由搭建
<PrivateRoute
isAuthenticated={jwt !== null}
path="/shoppingCart"
component={ShoppingCartPage}
/>
const PrivateRoute = ({ component, isAuthenticated, ...rest }: any) => {
const routeComponent = (props: any) => {
return isAuthenticated ? (
React.createElement(component, props)
) : (
<Redirect to={{ pathname: "/signIn" }} />
);
}
return <Route render={routeComponent} {...rest} />;
}
記錄頁(yè)面來(lái)源
fromPage
toPage
react-redux
數(shù)據(jù)傳遞
傳遞順序: dispatch => action => reducer => state
// 1-1 dispatch
import { Dispatch } from "react";
const dispatch = useDispatch()
dispatch(addLanguageActionCreator("新語(yǔ)言", "new_lang"));
dispatch(changeLanguageActionCreator(e.key));
// 1-2 action
export const CHANGE_LANGUAGE = 'change_language'
export const ADD_LANGUAGE = 'add_language'
interface ChangeLanguageAction {
type: typeof CHANGE_LANGUAGE,
payload: 'zh' | 'en'
}
interface AddLanguageAction {
type: typeof ADD_LANGUAGE;
payload: {name: string; code: string};
}
export type LanguageActionTypes = ChangeLanguageAction | AddLanguageAction;
export const changeLanguageActionCreator = (
languageCode: 'zh' | 'en'
): ChangeLanguageAction => {
return {
type: CHANGE_LANGUAGE,
payload: languageCode
}
}
export const addLanguageActionCreator = (
name: string,
code: string
) : AddLanguageAction => {
return {
type: ADD_LANGUAGE,
payload: {name, code}
}
}
// 1-3 reducer: 處理action過(guò)來(lái)的內(nèi)容
languageReducer
// 定義state的默認(rèn)值
export interface languageState {
language: 'en' | 'zh',
languageList: { name: string, code: string }[]
}
const defaultState: languageState = {
language: 'zh',
languageList: [{
name: '中文',
code: 'zh'
}, {
name: 'English',
code: 'en'
}]
}
// 定義reducer
const languageReducer = (state = defaultState, action: LanguageActionTypes) => {
console.log('action', action)
switch (action.type) {
case CHANGE_LANGUAGE:
i18n.changeLanguage(action.payload);
return { ...state, language: action.payload };
case ADD_LANGUAGE:
return {
...state,
languageList: [...state.languageList, action.payload]
};
default:
return state
}
}
// 1-4 state
import { useSelector } from "../../redux/hooks";
const language = useSelector((state) => state.language)
const languageList = useSelector((state) => state.languageList)
其他
css模塊化
// 1肴甸、使用寂殉,配置custom.d.ts即可
// 1-1 配置 custom.d.ts
declare module '*.css' {
const css : { [key: string]: string };
export default css
}
// 1-2 使用
import style from './index.css'
<div className={styles.app}/>
// 2、 vscode提示 建議配合typescript-plugin-css-modules 使用原在, 會(huì)有類名提示友扰;
// 2-1 按照插件 typescript-plugin-css-modules
npm install --save-dev typescript-plugin-css-modules
// 2-2 tsconfig.json配置:
"plugins": [{
"name": "typescript-plugin-css-modules"
}]
// 2-3 .vscode的settings.json配置
{
<!--"typescript.tsserver.pluginPaths": ["typescript-plugin-css-modules"]-->
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
}
setState是同步還是要異步?
答:同步執(zhí)行庶柿,異步更新村怪。
setState0本身并非異步,但對(duì)statel的處理機(jī)制給人一種異步的假象
state處理一般發(fā)生在生命周期變化的時(shí)候浮庐。
setState如何實(shí)現(xiàn)異步開(kāi)發(fā)甚负?
// 第二個(gè)參數(shù)傳入一個(gè)回調(diào)函數(shù),獲取修改后的state值
this.setState({ count: this.state.count + 1 }, () => {
console.log('count-1', this.state.count) // 1
})
console.log('count-0', this.state.count) // 0
// 第一個(gè)參數(shù)直接傳入一個(gè)回調(diào)函數(shù)审残,獲取上一個(gè)state值
this.setState({ count: this.state.count + 1 })
this.setState((preState, preProps) => {
console.log('count-1', preState.count) // 1
return { count: preState.count + 1 }
}, () => {
console.log('count-2', this.state.count) // 2
})
省略any的配置
tsconfig.json 配置noImplicitAny字段梭域,即可不用寫(xiě)any了。
"noImplicitAny": false
components組件化
適用場(chǎng)景:公共組件的引入與導(dǎo)出维苔;
適用場(chǎng)景:公共組件的引入與導(dǎo)出碰辅;
導(dǎo)出操作:
// components文件夾 -> header文件夾 -> index.ts
export * from './Header'
// components文件夾 -> footer -> footer.ts
export * from './Footer'
// components文件夾 -> index.ts
export * from './footer'
export * from './header'
引入操作:
// app.tsx文件夾
import { Header, Footer } from './components'
【end】