美文网首页
react17学习的简单小记

react17学习的简单小记

作者: 付出的前端路 | 来源:发表于2022-06-26 14:06 被阅读0次

    目录

    一、前言

    二、通信

    三、生命周期

    四、基础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】

    相关文章

      网友评论

          本文标题:react17学习的简单小记

          本文链接:https://www.haomeiwen.com/subject/xpcgvrtx.html