react17學(xué)習(xí)的簡(jiǎn)單小記

目錄

一枫耳、前言

二即舌、通信

三辨宠、生命周期

四饥漫、基礎(chǔ)api的使用

五、react-router

六薛窥、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;


? Back to top

生命周期

image.png

Mounting:創(chuàng)建虛擬DOM椒楣, 渲染UI

Updating: 更新虛擬DOM给郊, 重新渲染UI

Unmounting 刪除虛擬DOM, 移除UI

初始化 => 更新 => 銷毀


? Back to top

基礎(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。


? Back to top

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


? Back to top

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)



? Back to top

其他

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'


? Back to top

【end】

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市介时,隨后出現(xiàn)的幾起案子没宾,更是在濱河造成了極大的恐慌,老刑警劉巖沸柔,帶你破解...
    沈念sama閱讀 222,865評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件循衰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡褐澎,警方通過(guò)查閱死者的電腦和手機(jī)会钝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)工三,“玉大人迁酸,你說(shuō)我怎么就攤上這事〖笳” “怎么了奸鬓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,631評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)掸读。 經(jīng)常有香客問(wèn)我串远,道長(zhǎng)宏多,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,199評(píng)論 1 300
  • 正文 為了忘掉前任澡罚,我火速辦了婚禮伸但,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘留搔。我一直安慰自己更胖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布催式。 她就那樣靜靜地躺著函喉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荣月。 梳的紋絲不亂的頭發(fā)上管呵,一...
    開(kāi)封第一講書(shū)人閱讀 52,793評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音哺窄,去河邊找鬼捐下。 笑死,一個(gè)胖子當(dāng)著我的面吹牛萌业,可吹牛的內(nèi)容都是我干的坷襟。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼生年,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼婴程!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起抱婉,我...
    開(kāi)封第一講書(shū)人閱讀 40,174評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤档叔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后蒸绩,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體衙四,經(jīng)...
    沈念sama閱讀 46,699評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評(píng)論 3 343
  • 正文 我和宋清朗相戀三年患亿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了传蹈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,918評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡步藕,死狀恐怖惦界,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情咙冗,我是刑警寧澤表锻,帶...
    沈念sama閱讀 36,573評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站乞娄,受9級(jí)特大地震影響瞬逊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜仪或,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評(píng)論 3 336
  • 文/蒙蒙 一确镊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧范删,春花似錦蕾域、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,749評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至添忘,卻和暖如春采呐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搁骑。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,862評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工斧吐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仲器。 一個(gè)月前我還...
    沈念sama閱讀 49,364評(píng)論 3 379
  • 正文 我出身青樓煤率,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親乏冀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蝶糯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評(píng)論 2 361

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