react17学习的简单小记

目录

一、前言

二、通信

三、生命周期

四、基础api的使用

五、react-router

六、react-redux

六、其他

</details>

前言

环境

"react": "^17.0.2" "redux": "^4.1.2"

REACT17版本的新变化

虽然没有新功能, 但具有战略意义;

事件委托机制改变
向原生浏览器靠拢

useEffect清理操作改为异步操作;
JSX不可返回undefined

总结:没有新功能,允许多版本混用,逐步升级。

通信

父子组件传递props

父组件

<Robot id="{123}" name="路线评价" email="height@163.com"/>

子组件

// 定义接口
interface RobotProps {
  id: number;
  name: string;
  email: string;
}

// 直接解构使用
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:创建虚拟DOM, 渲染UI

Updating: 更新虚拟DOM, 重新渲染UI

Unmounting 删除虚拟DOM, 移除UI

初始化 => 更新 => 销毁


⬆ Back to top

基础api的使用

hooks

hooks的本质是一类特殊的函数,为你的函数型式组件注入特殊的功能; hooks的目的是给函数式组件加上状态;

常见的钩子函数:

  • useState
  • useEffect
  • useContext

useState

useState常见用法

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

输入参数一样,输出结果不一样的情况。就是副作用。

比如:

Ajax,修改DOM,甚至是console.log;

REACT: state的状态改变, 生命周期,构建函数;

副作用会给系统添加不可控的因素,但是不要害怕。

useEffect常见用法

// 1. 每次UI渲染,都会触发
  useEffect(() => {
    console.log('useEffect')
  })

// 2. 相当于生命周期 componentDidMount,是 DOM挂载后,只执行一次
// 使用场景:多数用在 fetch数据 的时候
useEffect(() => {
  fetch("https://jsonplaceholder.typicode.com/users")
    .then((response) => {
      return response.json()
    })
    .then((data) => setRobotGallery(data))
}, [])
 
 // 3. 相当于watch监听器
useEffect(() => {
  console.log('useEffect')
  document.title = `点击${count}次`
}, [count]) 
 

useContext

爷孙组件通信

以前: context Provider 和 Consumer

现在:context Provide 和useContext

作用:类似于一个统一的状态管理。后面可以用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>
  )
}

上面代码优化一下,将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是函数
  • 命名以"use"开头
  • 内部可调用其他Hook函数
  • 并非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)}>加入购物车</button>
    </div>
  )
}


export default RobotDicount;


// 定义自定义hooks 导出一个函数
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中用于复用组件逻辑的一种高级技巧。HOC自身不
是React API的一部分,它是一种基于React的组合特性而形成的设计模式。

具体而言,高阶组件是参数为组件,返回值为新组件的函数。

为什么要使用高阶组件?

  • 抽取重复代码,实现组件复用
  • 条件渲染,控制渲染组件的渲染逻辑(渲染劫持)
  • 捕获/劫持被处理组件的生命周期
// HOC组件 一般使用with开头, 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)}>加入购物车</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} />
  }
}

对比hook和HOC

需要生命周期的时候用HOC,只是单纯的公共函数方法用hook。


⬆ Back to top

react-router

路由跳转

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()

携带参数

1.query

// 配置路由 router.tsx 配置路由页面
<Route path="/detail/:touristRouteId" component={DetailPage}></Route>

// 跳转路由 productList.tsx页面
history.push(`detail/${id}`)

// 获取参数 deatail.tsx页面 

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

记录页面来源

fromPage

toPage


⬆ Back to top

react-redux

数据传递

传递顺序: dispatch => action => reducer => state

// 1-1 dispatch
import { Dispatch } from "react";

const dispatch = useDispatch()

dispatch(addLanguageActionCreator("新语言", "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过来的内容
languageReducer

// 定义state的默认值
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 使用, 会有类名提示;
// 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是同步还是要异步?

答:同步执行,异步更新。

setState0本身并非异步,但对statel的处理机制给人一种异步的假象
state处理一般发生在生命周期变化的时候。

setState如何实现异步开发?

// 第二个参数传入一个回调函数,获取修改后的state值
this.setState({ count: this.state.count + 1 }, () => {
  console.log('count-1', this.state.count) // 1
})
console.log('count-0', this.state.count) // 0


// 第一个参数直接传入一个回调函数,获取上一个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字段,即可不用写any了。

"noImplicitAny": false

components组件化

适用场景:公共组件的引入与导出;
适用场景:公共组件的引入与导出;

导出操作: 

// 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】

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容

  • 一.JSX的优点 1.书写简单 以html的方式书写代码 2.直接在jsx标签上注册事件 3.可以使用大括号语法 ...
    糖醋鱼_阅读 919评论 0 10
  • React Native Awesome 汇集了各类react-native学习资料、工具、组件、开源App、资源...
    CrazyCodeBoy阅读 10,972评论 10 264
  • React的学习资源 这个文章好久没有更新了,资源算比较老旧的了,毕竟前端更新还是非常快的。 半年不学习,都不知道...
    izhongxia阅读 23,190评论 11 629
  • github地址 React-Native学习指南 本指南汇集React-Native各类学习资源,给大家提供便利...
    izhongxia阅读 4,666评论 2 96
  • 本指南汇集React-Native各类学习资源,给大家提供便利。指南正在不断的更新,大家有好的资源欢迎Pull R...
    熊凯阅读 5,564评论 1 62