<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一名 Vue 程序員總結的 React 基礎

          共 19921字,需瀏覽 40分鐘

           ·

          2021-07-04 06:33

          (給前端大學加星標,提升前端技能.

          一、生命周期

          React 生命周期圖解[1]

          我已經(jīng)把這張圖印在腦子里面了,沒事就自己畫畫,中間發(fā)散一些自己的思考。u1s1,不知道 react 的生命周期命名為什么要怎么長~~~, 小程序,vue 的都比較短。畢竟使用的頻率還是很高的,Hooks 除外。

          image.png

          1、constructor

          constructor 是類通用的構造函數(shù),常用于初始化,算是生命周期的一環(huán)。React 后來的版本中類組件也可以不寫。

          注意:在構造函數(shù)中使用時,super 關鍵字將單獨出現(xiàn),并且必須在使用 this 關鍵字之前使用。super 關鍵字也可以用來調用父對象上的函數(shù)。MDN 說明[2]

          class JJTest extends React.Component {
            // constructor 寫法
            constructor(props) {
              super(props);
              this.state = {
                count0,
              };
              this.handleClick = this.handleClick.bind(this);
            }
            // 直接聲明
            state = {
              count0,
            };
          }

          2、getDerivedStateFromProps

          觸發(fā)時機:state 變化、props 變化、forceUpdate,如上圖。

          這是一個靜態(tài)方法, 是一個和組件自身"不相關"的角色. 在這個靜態(tài)方法中, 除了兩個默認的位置參數(shù) nextProps 和 currentState 以外, 你無法訪問任何組件上的數(shù)據(jù)。

          // 初始化/更新時調用
          static getDerivedStateFromProps(nextProps, currentState) {
            console.log(nextProps, currentState, "getDerivedStateFromProps方法執(zhí)行");
            // 返回值是對currentState進行修改
            return {
              fatherText: nextProps.text,
            };
          }

          3、render

          render 函數(shù)返回的 JSX 結構,用于描述具體的渲染內(nèi)容, render 被調用時,它會檢查 this.props 和 this.state 的變化并返回以下類型之一:

          • React 元素。通常通過 JSX 創(chuàng)建。例如,

            會被 React 渲染為 DOM 節(jié)點, 會被 React 渲染為自定義組件,無論是

            還是 均為 React 元素。

          • 數(shù)組或 fragments。使得 render 方法可以返回多個元素。欲了解更多詳細信息,請參閱 fragments 文檔。

          • Portals。可以渲染子節(jié)點到不同的 DOM 子樹中。欲了解更多詳細信息,請參閱有關 portals 的文檔

          • 字符串或數(shù)值類型。它們在 DOM 中會被渲染為文本節(jié)點

          • 布爾類型或 null。什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 為布爾類型。)

          注意:如果 shouldComponentUpdate() 返回 false,則不會調用 render()。

          Hooks 不需要寫 render 函數(shù)。要注意的一點是,即使 Hooks 不需要寫 render, 沒有用到 React.xxx,組件內(nèi)還是要import React from "react";的(至于原因,后續(xù)深入 Hooks 學一下,大哥們也可以解釋下)。React 官方也說了,后續(xù)的版本會優(yōu)化掉這一點。

          4、componentDidMount

          主要用于組件加載完成時做某些操作,比如發(fā)起網(wǎng)絡請求或者綁定事件。當做 vue 的 mounted 用就行了,這里需要注意的是:

          componentDidMount() 里直接調用 setState()。它將觸發(fā)額外渲染,也就是兩次 render,不過問題不大,主要還是理解。

          5、shouldComponentUpdate

          該方法通過返回 true 或者 false 來確定是否需要觸發(fā)新的渲染。因為渲染觸發(fā)最后一道關卡,所以也是性能優(yōu)化的必爭之地。通過添加判斷條件來阻止不必要的渲染。注意:首次渲染或使用 forceUpdate() 時不會調用該方法。

          React 官方提供了一個通用的優(yōu)化方案,也就是 PureComponent。PureComponent 的核心原理就是默認實現(xiàn)了 shouldComponentUpdate 函數(shù),在這個函數(shù)中對 props 和 state 進行淺比較,用來判斷是否觸發(fā)更新。

          當然 PureComponent 也是有缺點的,使用的時候一定要注意:由于進行的是淺比較,可能由于深層的數(shù)據(jù)不一致導致而產(chǎn)生錯誤的否定判斷,從而導致頁 面得不到更新。不適合使用在含有多層嵌套對象的 state 和 prop 中。

          shouldComponentUpdate(nextProps, nextState) {
            // 淺比較僅比較值與引用,并不會對 Object 中的每一項值進行比較
            if (shadowEqual(nextProps, this.props) || shadowEqual(nextState, this.state) ) {
              return true
            }
            return false
          }

          6、getSnapshotBeforeUpdate

          在 DOM 更新前被調用,返回值將作為 componentDidUpdate 的第三個參數(shù)。

          getSnapshotBeforeUpdate(prevProps, prevState) {
              console.log("getSnapshotBeforeUpdate方法執(zhí)行");

              return "componentDidUpdated的第三個參數(shù)";
          }

          7、componentDidUpdate

          首次渲染不會執(zhí)行此方法。可以使用 setState,會觸發(fā)重渲染,但一定要小心使用,避免死循環(huán)

           componentDidUpdate(preProps, preState, valueFromSnapshot) {
              console.log("componentDidUpdate方法執(zhí)行");

              console.log("從 getSnapshotBeforeUpdate 獲取到的值是", valueFromSnapshot);
            }

          8、componentWillUnmount

          主要用于一些事件的解綁,資源清理等,比如取消定時器,取消訂閱事件

          小結

          生命周期一定要好好理解,一定要動手寫,看一下每種情況下,生命周期的執(zhí)行結果。上述代碼中在React-TypeScript 倉庫[3]中都有,可以 clone 下來跑跑看,或者直接訪問俊劫學習系統(tǒng) LifeCycle[4]。還有些其他的生命周期,componentDidCatch, UNSAFE_componentWillMount()等等,簡單了解下就行。

          二、JSX

          1、循環(huán)列表

          jsx 中一般用 map 來渲染列表循環(huán)類的,vue 中直接在 template 中寫 v-for 即可

          {
            list.map((item, index) => {
              return <AppCard key={index} title={item.title} onClick={item.onClick} />;
            });
          }

          2、樣式

          (1)className

          單獨寫一個 class 是可以的,動態(tài)拼接需要借助 classnames[5]

          import style from './style.css'

          <div className={style.class1 style.class2}</div>

          (2)style

          需要注意的:兩個括號(樣式被當做一個對象來解析),類似-連接的樣式屬性需要轉換成小駝峰寫法。

          <div style={{ marginTop: 8 }}>樣式</div>

          (3)css 隔離

          u1s1,css 隔離這塊還是 vue 的 scoped 好用

          • css-module

          create-react-app 中內(nèi)置了使用 CSS Modules 的配置,和 vue 的 scoped 原理相似,都是在生成的 class 后面加了 hash 值

          // style.module.css
          .text {
              color: blue
          }
          // app.tsx
          import s from "./style.module.css";
          class App extends Component {
            render() {
              return <div className={s.text}>css-module text</div>;
            }
          }
          // 編譯后
          .text_3FI3s6uz {
              color: blue;
          }
          • styled-components

          目前社區(qū)里最受歡迎的一款 CSS in JS 方案,個人感覺有點別扭,不太喜歡

          //引入styled-components
          import styled from "styled-components";

          //修改了div的樣式
          const Title = styled.div`
            font-size: 30px;
            color: red;
          `
          ;
          class App extends Component {
            render() {
              return (
                <>
                  <Title>CSS in JS 方案</Title>
                </>

              );
            }
          }

          3、一個 JSX

          剛開始從 vue 轉過來會有些不適應(話說有多少人直接在 vue 里面寫 JSX 的),之前用的都是 Vue Sfc 寫法,當然多寫寫就熟悉了。至于 React 采用 JSX 的優(yōu)劣勢,評論區(qū)各抒己見哈。

          代碼對應頁面預覽[6]

          image.png
          render() {
              return (
                <>
                  <Alert title="控制臺展示父子組件生命周期的過程" />
                  <div className="fatherContainer">
                    <Button onClick={this.changeText} type="primary">
                      修改父組件文本內(nèi)容
                    </Button>
                    <Button onClick={this.hideChild} type="danger">
                      {this.state.hideChild ? "顯示" : "隱藏"}子組件
                    </Button>
                    {this.state.hideChild ? null : (
                      <LifeCycle text={this.state.text} count={1} />
                    )}
                  </div>
                  <div>
                    <BlockLoading loading={this.state.loading} iconSize={64} />
                    <iframe
                      src={this.state.lifeCycle}
                      title="navigation"
                      width="100%"
                      height="600px"
                      onLoad={this.onLoading}
                      onError={this.onLoading}
                    >
          </iframe>
                  </div>
                </>

              );
            }

          三、基礎組件

          組件這塊,個人感覺和 vue 差別還是比較大的,顆粒度更細致,當然也增加了一定難度。這里就簡單例舉一個TS版本的,帶 Icon 的標題組件

          import cn from "classnames";
          import React from "react";
          import "./style/index.less";
          import { Icon,IIconProps } from "zent";

          interface IProps {
            title: string;
            iconType?: IIconProps['type'];
            isShowIcon?: boolean;
            iconClassName?: string;
            titleClassName?: string;
          }

          export const ContentTitle: React.FC<IProps> = (props) => {
            const { title, iconType = 'youzan', isShowIcon = false , iconClassName, titleClassName, ...popProps } = props;

            return (
              <div className={cn("content-title", titleClassName)}>
                {title}
                {isShowIcon && <Icon
                  className={cn("content-title__icon", iconClassName)}
                  {...popProps}
                  type={iconType}
                />
          }
              </div>

            );
          };

          export default ContentTitle;

          四、高階組件 HOC

          1、含義

          vue mixins 相同,都是為了解決代碼復用的問題,但 react 中已經(jīng)廢棄 mixins,vue 中也不推薦使用。主要是會帶來命名沖突,相互依賴,不方便維護等一些缺點。

          高階組件其實就是處理 react 組件的函數(shù),簡單理解就是和 ES6 中提供的 export/import 作用相似,不同點在于:高階組件會進行加工后再導出你需要的東西。類似于方程式:y = ax + b, x 是入口(組件),會根據(jù) a 和 b 進行計算,得到最終的 y(處理后的組件) 給到你用。

          2、Demo

          官網(wǎng)的實現(xiàn) Demo: 高階組件[7]

          一個簡單的高階組件(實現(xiàn)有兩種方式:屬性代理和反向繼承):

          // 屬性代理: 組件屬性的一些修改
          const JJHOC = (WrappedComponent) => {
            return class NewComponent extends React.Component {
              render() {
                const newProps = { type"HOC" };
                return <WrappedComponent {...this.props} {...newProps} />;
              }
            };
          };
          // 反向繼承: 在render() 方法中返回 super.render() 方法
          const JJHOC = (WrappedComponent) => {
            return class NewComponent extends WrappedComponent {
              render() {
                return super.render();
              }
            };
          };

          3、常用 HOC

          • react-router withRouter: 可獲取 history,一些路由信息
          • redux connect 連接 React 組件與 Redux store,給組件掛載 dispatch 方法。

          五、組件通信

          1、props

          和 vue 不同的是,react props 傳值可以直接寫,不需要聲明。在 props 上掛載 function,就相當于是 vue 的$emit。同樣需要注意的是子組件不可以修改 props 的值

          import React from "react";

          function Child(props{
            const sendMsg = (msg) => {
              props.onClick("子組件的消息");
            };
            return (
              <div>
                <div>子組件標題:{props.title}</div>
                <button onClick={() => sendMsg("子組件消息")}> 子傳父 </button>
              </div>

            );
          }

          function Father({
            const onClick = (msg) => {
              console.log(`父組件接收:${msg}`);
            };
            return (
              <div>
                <Child title="組件props傳值測試" onClick={onClick}></Child>
              </div>

            );
          }

          export default Father;

          2、context

          React Context 官網(wǎng)說明[8],跨組件傳值。創(chuàng)建了一個上下文,同 context 內(nèi)的組件都可以 通過 Provider 配合 value 使用數(shù)據(jù)

          import * as React from "react";
          import { Button } from "zent";
          // Context 可以讓我們無須明確地傳遍每一個組件,就能將值深入傳遞進組件樹。
          // 為當前的 theme 創(chuàng)建一個 context(“primary”為默認值)。
          const ThemeContext = React.createContext("primary");
          export default class App extends React.Component {
            render() {
              // 使用一個 Provider 來將當前的 theme 傳遞給以下的組件樹。
              // 無論多深,任何組件都能讀取這個值。
              // 在這個例子中,我們將 danger 作為當前的值傳遞下去。
              return (
                <ThemeContext.Provider value="danger">
                  <Toolbar />
                </ThemeContext.Provider>

              );
            }
          }

          // 中間的組件再也不必指明往下傳遞 theme 了。
          function Toolbar({
            return (
              <div>
                <ThemedButton />
              </div>

            );
          }

          class ThemedButton extends React.Component {
            // 指定 contextType 讀取當前的 theme context。
            // React 會往上找到最近的 theme Provider,然后使用它的值。
            // 在這個例子中,當前的 theme 值為 “danger”。
            static contextType = ThemeContext;
            render() {
              return <Button type={this.context}>context測試</Button>;
            }
          }

          3、Redux

          Redux 中文文檔[9]

          redux 的三大核心:

          • action:action 可以說是一個動作,用來描述將要觸發(fā)的事件。
          • state:單一數(shù)據(jù)源,用來存儲我們的數(shù)據(jù)。
          • reducer:通過觸發(fā)的 action 事件來改變 state 的值。

          不一定非要用,很多項目 context 就已經(jīng)夠用了

          (1)掛載

          使用 createStore 創(chuàng)建一個 store 并通過 Provider 把它放到容器組件中

          // index.js
          const store = createStore(appReducer);

          ReactDOM.render(
            <Provider store={store}>
              <App />
            </Provider>
          ,
            document.getElementById("root");
          );

          (2)創(chuàng)建修改的方法

          和 vuex 相似,都是通過 action 來修改數(shù)據(jù)

          // action.js
          export const addConst = (payload) => {
            type"ADD_CONST",
          }

          export const minusConst = (payload) => {
           type"MINUS_CONST",
          }

          (3)創(chuàng)建一個 store 集合

          當 dispatch 觸發(fā)相應的方法,執(zhí)行對應的操作,修改 store 數(shù)據(jù)。

          // appReducer.js
          const initialState = { count0 };
          const reducer = (state = initialState, action) => {
            switch (action.type) {
              case "ADD_CONST":
                return { count: count + 1 };
              case "MINUS_CONST":
                return { count: count - 1 };
              default:
                return state;
            }
          };
          export default reducer;

          (4)組件中 redux 使用姿勢

          import React from "react";
          import { connect } from "react-redux";

          const ReduxDemo: React.FC = (props) => {
            const addCount = () => {
              const { dispatch } = props;
              dispatch({
                type"ADD_CONST",
              });
            };

            const minusCount = () => {
              const { dispatch } = props;
              dispatch({
                type"MINUS_CONST",
              });
            };
            return (
              <div>
                <button onClick={addCount}></button>
                <button onClick={minusCount}></button>
                <div>{props.state}</div>
              </div>

            );
          };

          const mapStateToProps = (state) => {
            return {
              count: state.count,
            };
          };
          export default connect(mapStateToProps)(ReduxDemo);

          六、組件校驗

          React 官網(wǎng) 使用 PropTypes 進行類型檢查[10] react props 不是必須聲明的,但是如果項目規(guī)范起來,就需要在 propTypes 中聲明 props 類型,注意需要引入prop-types

          不過現(xiàn)在更多的是通過 typescript 來校驗類型了,開發(fā)階段就能發(fā)現(xiàn)問題。

          import * as React from "react";
          import PropTypes from "prop-types";

          interface IProps {
            name: string;
          }

          const PropsDemo: React.FC<IProps> = ({ name }) => {
            return <h1>Hello, {name}</h1>;
          };

          PropsDemo.propTypes = {
            name: PropTypes.string,
          };

          七、React Router

          • React Router 官網(wǎng)[11] 英文版
          • React Router 中文文檔[12] 感覺寫的不是很清楚

          1、注意

          • react-router: 實現(xiàn)了路由的核心功能, react-router 3.x  版本還包括操作 dom 的方法,4.x 以上就沒有了。
          • react-router-dom: 基于 react-router,加入了在瀏覽器運行環(huán)境下的一些功能,例如:Link 組件,會渲染一個 a 標簽,Link 組件源碼 a 標簽行; BrowserRouter 和 HashRouter 組件,前者使用 pushState 和 popState 事件構建路由,后者使用 window.location.hash 和 hashchange 事件構建路由。
          • react-router-native: 基于 react-router,類似 react-router-dom,加入了 react-native 運行環(huán)境下的一些功能

          2、一個 Demo

          import React, { Component } from "react";
          import Admin from "./pages/admin/admin";
          import Login from "./pages/login/Login";
          import { HashRouter, Route, Switch } from "react-router-dom";
          class App extends Component {
            render() {
              return (
                <HashRouter>
                  <Switch>
                    <Route path="/" component={Admin}></Route>
                    <Route path="/login" component={Login}></Route>
                  </Switch>
                </HashRouter>

              );
            }
          }

          export default App;

          3、路由傳參

          (1)params

          // router
          <Route path='/path/:id' component={Path}/>
          // 傳參
          <link to="/path/789">xxx</Link>
          this.props.history.push({pathname:`/path/${id}`});
          // 獲取
          this.props.match.params.id

          (2)query

          // router
          <Route path='/query' component={Query}/>
          // 傳參
          <Link to={{ path : '/query' , query : { id : '789' }}}>xxx</Link>

          this.props.history.push({pathname:"/query",query: { id : '789' }});
          // 獲取
          this.props.location.query.id

          (3)Hooks

          // 跳轉
          let history = useHistory();
          history.push("/");

          // 獲取
          useLocation();
          useParams();
          useRouteMatch();

          4、exact 屬性

          exact 是 Route 下的一條屬性,一般而言,react 路由會匹配所有匹配到的路由組價,exact 能夠使得路由的匹配更嚴格一些。

          exact 的值為 bool 型,為 true 是表示嚴格匹配,為 false 時為正常匹配。

          如在 exact 為 true 時,’/link’與’/’是不匹配的,但是在 false 的情況下它們又是匹配的。<Route path="/home" component={Home} exact></Route>

          八、總結

          學完生命周期,多練習 JSX,配合 React Router 和 Redux 多寫寫組件,基本就能上手開發(fā)了。沒有過多的 API 需要學習,寫起來也比較自由。React 雖然生態(tài)強大,選著性比較多,但是這樣產(chǎn)生了一個問題:什么是 React 的最佳實踐?


          相關代碼倉庫:


          倉庫:React-TypeScript

          https://github.com/alexwjj/React-TypeScript


          線上預覽:俊劫 React 學習系統(tǒng)

          https://alexwjj.github.io/study

          參考資料

          [1]

          React 生命周期圖解: https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

          [2]

          MDN 說明: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/super#%E6%8F%8F%E8%BF%B0

          [3]

          React-TypeScript 倉庫: https://github.com/alexwjj/React-TypeScript

          [4]

          俊劫學習系統(tǒng) LifeCycle: https://alexwjj.github.io/study/#/demo

          [5]

          classnames: https://github.com/JedWatson/classnames

          [6]

          代碼對應頁面預覽: https://alexwjj.github.io/study/#/demo

          [7]

          高階組件: https://zh-hans.reactjs.org/docs/higher-order-components.html

          [8]

          React Context 官網(wǎng)說明: https://zh-hans.reactjs.org/docs/context.html

          [9]

          Redux 中文文檔: http://cn.redux.js.org/

          [10]

          React 官網(wǎng) 使用 PropTypes 進行類型檢查: https://zh-hans.reactjs.org/docs/typechecking-with-proptypes.html

          [11]

          React Router 官網(wǎng): https://reactrouter.com/web/guides/quick-start

          [12]

          React Router 中文文檔: http://react-guide.github.io/react-router-cn/

          轉自:掘金 -  俊劫

          https://juejin.cn/post/6960556335092269063

          點贊和在看就是最大的支持??

          瀏覽 72
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕日韩在线观看视频 | 久久天天弄 | 操片 | 欧美精品操逼视频 | 亚洲高清A∨ |