91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用JS代碼構建React

發布時間:2021-08-26 16:38:26 來源:億速云 閱讀:142 作者:chen 欄目:web開發

這篇文章主要講解了“怎么用JS代碼構建React”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么用JS代碼構建React”吧!

我們將構建什么功能?

  •  JSX

  •  函數組件

  •  類組件

  •  生命周期鉤子函數

我們不會構建什么?

虛擬DOM

再次為了簡單起見,我們不會在本文中實現我們自己的虛擬DOM,我們將使用 snabbdom ,有趣的是,Vue.js 虛擬DOM借鑒了它,你可以在這里讀更多關于 snabbdom 的內容: https://github.com/snabbdom/s...

React Hooks

有些人可能對此感動失望,但是,一口吃不成一個胖子,我們需要一步一步來,因此讓我們首先構建基本的東西,然后再在此基礎上加以補充。我計劃后續文章中在我們此次構建的內容之上,編寫我們自己的 React Hooks 以及虛擬DOM,

可調試性

這是增加任何庫或框架的復雜度的關鍵部分之一,由于我們只是出于娛樂目的而做,因此我們可以放心地忽略 React 提供的可調試性功能,例如 dev tools 和分析器。

性能和兼容性

我們不會過于關注我們的庫的性能,我們只想構建能正常運行的庫。讓我們也不要費力地確保它可以在市場上的所有瀏覽器上使用,只有能夠在某些現代瀏覽器上可以使用,那就已經很好了。

讓我們開始動手

在開始之前,我們需要一個支持ES6,自動熱更新的腳手架。我已經創建了一個非常基礎的 webpack 腳手架,你可以進行克隆和設置: https://github.com/ameertheha...

JSX

JSX 是一個開放標準,不僅限于 React,我們可以在沒有 React 的情況下使用它,它比你想象得還有容易。想要了解如何讓我們的庫支持 JSX ,我們首先需要看看在我們使用 JSX 時背后究竟發生了什么。

const App = (      <div>          <h2 className="primary">QndReact is Quick and dirty react</h2>          <p>It is about building your own React in 90 lines of JavsScript</p>      </div>  );  // 上面的 jsx 被轉換成下面這樣:  /**   * React.createElement(type, attributes, children)   */  var App = React.createElement(      "div",      null,      React.createElement(          "h2",          {              className: "primary"          },          "QndReact is Quick and dirty react"      ),      React.createElement(          "p",          null,          "It is about building your own React in 90 lines of JavsScript"      )  );

正如你看到的,每個 JSX 元素都通過 @babel/plugin-transform-react-jsx 插件轉換為了 React.createElement(...) 函數調用的形式,你可以在這里使用 JSX 進行更多的轉換

為了使上述轉換運行正常,在編寫 JSX 時,你需要引入 React,你就是為什么當你不引入 React 時,編寫 JSX 會出現錯誤的原因。 @babel/plugin-transform-react-jsx 插件已經添加在了我們的項目依賴中,下面我們先安裝一下依賴

npm install

把項目的配置增加到 .babelrc 文件中:

{      "plugins": [          [              "@babel/plugin-transform-react-jsx",              {                  "pragma": "QndReact.createElement", // default pragma is React.createElement                  "throwIfNamespace": false // defaults to true              }          ]      ]  }

此后,只要 Babel 看到 JSX ,它就會調用 QntReact.createElement(...),但是我們還未定義此函數,現在我們將其寫到 src/qnd-react.js 中。

const createElement = (type, props = {}, ...children) => {      console.log(type, props, children);  };  // 像 React.createElement 一樣導出  const QndReact = {      createElement  };  export default QndReact;

我們在控制臺打印出了傳遞給我們的 type 、 props、 children。為了測試我們的轉換是否正常,我們可以在 src/index.js 中編寫一些 JSX 。

// QndReact 需要被引入  import QndReact from "./qnd-react";  const App = (      <div>          <h2 className="primary">              QndReact is Quick and dirty react          </h2>          <p>It is about building your own React in 90 lines of JavsScript</p>      </div>  );

啟動項目: npm start,在瀏覽器輸入localhost:3000,現在你的控制臺看起來應該與下圖類似:

怎么用JS代碼構建React

根據以上信息,我們可以使用 snabbdom 創建我們內部的 虛擬DOM節點 ,然后我們才能將其用于我們的協調(reconciliation) 過程,可以使用如下的命令安裝 snabbdom:

npm install snabbdom

當 QndReact.createElement(...) 被調用時嗎,創建和返回 虛擬DOM節點。

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      return h(type, { props }, children);  };  const QndReact = {      createElement  };  export default QndReact;

很好,現在我們可以解析 JSX 并創建自己的虛擬DOM節點,但是仍然無法在瀏覽器中呈現出來。為此,我們在 src/qnd-react-dom.js 添加一個 render 方法。

//src/qnd-react-dom.js  //React.render(<App />, document.getElementById('root'));  const render = (el, rootElement) => {      //將el渲染到rootElement的邏輯  }  const QndReactDom = {      render  }

與其我們自己去處理將元素放到 DOM 上的繁重工作,不如讓 snabbdom 去處理。為此我們可以引入模塊去初始化 snabbdom。snabbdom 中的模塊可以看做是插件,可以支持 snabbdom 做更多的事。

//src/qnd-react-dom.js  import * as snabbdom from 'snabbdom';  import propsModule from 'snabbdom/modules/props';  const reconcile = snabbdom.init([propsModule]);  const render = (el, rootDomElement) => {      //將el渲染到rootElement      reconcile(rootDomElement, el);  }  const QndReactDom = {      render  }  export default QndReactDom;

我們使用這個新的 render 函數去 src/index 中去做一些魔法。

//src/index.js  import QndReact from "./qnd-react";  import QndReactDom from './qnd-react-dom';  const App = (      <div>          <h2 className="primary">              QndReact is Quick and dirty react          </h2>          <p>It is about building your own React in 90 lines of JavsScript</p>      </div>  );  QndReactDom.render(App, document.getElementById('root'));

瞧,我們的JSX已經可以渲染到屏幕上了。

怎么用JS代碼構建React

等下,這個有一個小問題,當我們兩次調用 render 時,我們會在控制臺看到一些奇怪的錯誤(譯者注: 可以在 index.js 中多次調用 render,查看控制臺錯誤),背后的原因是我們只有在第一次渲染時,可以在真實的DOM節點上調用 reconcile 方法,然后,我們應該在之前返回的虛擬DOM節點上調用。

//src/qnd-react-dom.js  import * as snabbdom from 'snabbdom';  import propsModule from 'snabbdom/modules/props';  const reconcile = snabbdom.init([propsModule]);  let rootVNode;  //QndReactDom.render(App, document.getElementById('root'))  const render = (el, rootDomElement) => {      if(rootVNode == null) {          //第一次調用 render 時          rootVNode = rootDomElement;      }      rootVNode = reconcile(rootVNode, el);  }  const QndReactDom = {      render  }  export default QndReactDom;

很開心,我們的應用程序中有一個能正常工作的 JSX 渲染,現在讓我們開始渲染一個函數組件,而不僅僅是一些普通的 HTML。

讓我們向 src/index.js 添加一個 Greeting 函數組件,如下所示:

//src/index.js  import QndReact from "./qnd-react";  import QndReactDom from './qnd-react-dom';  const Greeting = ({ name }) => <p>Welcome {name}!</p>;  const App = (      <div>          <h2 className="primary">              QndReact is Quick and dirty react          </h2>          <p>It is about building your own React in 90 lines of JavsScript</p>          <Greeting name={"Ameer Jhan"} />      </div>  );  QndReactDom.render(App, document.getElementById('root'));

此時,在控制臺會出現以下錯誤:

怎么用JS代碼構建React

我們可以在 QndReact.createElement(...) 方法中打印出數據看一下原因。

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      console.log(type, props, children);      return h(type, { props }, children);  };  ...

怎么用JS代碼構建React

如果可以看到,函數組件傳遞過來的 type 是一個JS函數。如果我們調用這個函數,就能獲得組件希望渲染的 HTML 結果。

我們根據 type 參數的類型,如果是函數類型,我們就調用這個函數,并將 props 作為參數傳給它,如果不是函數類型,我們就當作普通的 HTML 元素處理。

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };  const QndReact = {      createElement  };  export default QndReact;

歡呼!我們的函數組件已經可以正常工作了。

怎么用JS代碼構建React

我們已經完成了很多,讓我們深吸一口氣,喝杯咖啡,因為我們已經差不多實現了 React,不過我們還需要攻克類組件。

我們首先在 src/qnd-react.js 中創建 Component 基類:

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };  class Component {      constructor() { }      componentDidMount() { }      setState(partialState) { }      render() { }  }  const QndReact = {      createElement,      Component  };  export default QndReact;

現在我們在 src/counter.js 中編寫我們的第一個 Counter 類組件:

//src/counter.js  import QndReact from './qnd-react';  export default class Counter extends QndReact.Component {      constructor(props) {          super(props);          this.state = {              count: 0          }      }      componentDidMount() {          console.log('Component mounted');      }      render() {          return <p>Count: {this.state.count}</p>      }  }

是的,我知道我們尚未在計數器中實現任何邏輯,但是別擔心,一旦我們的狀態管理系統運行正常,我們就會添加這些內容。現在,讓我們嘗試在 src/index.js 中渲染它。

//src/index.js  import QndReact from "./qnd-react";  import QndReactDom from './qnd-react-dom';  import Counter from "./counter";  const Greeting = ({ name }) => <p>Welcome {name}!</p>;  const App = (      <div>          <h2 className="primary">              QndReact is Quick and dirty react          </h2>          <p>It is about building your own React in 90 lines of JavsScript</p>          <Greeting name={"Ameer Jhan"} />          <Counter />      </div>  );  QndReactDom.render(App, document.getElementById('root'));

和料想中的一樣,又又又報錯了。

怎么用JS代碼構建React

上面的錯誤看起來是不是很熟悉,當你嘗試使用類組件而不集成自 React.Component 時,可能遇到過以上錯誤。要知道為什么會這樣,我們可以在 React.createElement(...) 中添加一個 console.log,如下所示:

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      console.log(typeof (type), type);      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };

我們來看看控制臺打印了什么內容。

怎么用JS代碼構建React

你可以看出 Counter 的 type 類型也是函數,這是因為 Babel 會將 ES6 類轉換為普通的 JS 函數,那么我們該如何類組件的情況呢。其實,我們可以在我們的 Component 基類中添加一個靜態屬性,這樣我們利用該屬性去檢查 type 參數是否是一個類。React 中也是相同的處理邏輯,你可以閱讀 Dan的博客

//src/qnt-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      console.log(typeof (type), type);      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  }; class Component {      constructor() { }      componentDidMount() { }      setState(partialState) { }      render() { }  }  //給 Component 組件添加靜態屬性來區分是函數還是類   Component.prototype.isQndReactClassComponent = true;  const QndReact = {      createElement,      Component  };  export default QndReact;

現在,我們在 QndReact.createElement(...) 中增加一些代碼來處理類組件。

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      console.log(type.prototype);      /**       * 如果是類組件       * 1.創建一個實例       * 2.調用實例的 render 方法       */      if (type.prototype && type.prototype.isQndReactClassComponent) {          const componentInstance = new type(props);          return componentInstance.render();      }      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };  class Component {      constructor() { }      componentDidMount() { }      setState(partialState) { }      render() { }  }  //給 Component 組件添加靜態屬性來區分是函數還是類   Component.prototype.isQndReactClassComponent = true;  const QndReact = {      createElement,      Component  };  export default QndReact;

現在,我們的類組件已經能夠渲染到瀏覽器上了:

怎么用JS代碼構建React

我們向類組件中增加 state,在此之前,我們需要知道,每次調用 this.setState({}) 時,如何更新 DOM 的責任是 react-dom 包,而不是 React 的責任。這是為了使 React 的核心部分,例如Component 類與平臺分離,從而提升代碼的可重用性。即在 ReactNative 中,你也可以使用同樣的 Component 類,react-native 負責如何更新UI。你可能會問自己:當調用 this.setState(...) 時,React 如何知道該怎么做,答案就是 react-dom 通過在 React 上設置了一個 __updater 屬性與 React 進行通信。Dan 對此也有出色的文章,你可以點擊閱讀。現在讓我們在 QndReactDom 中為 QndReact 添加 __updater 屬性。

//src/qnd-react-dom.js  import QndReact from './qnd-react';  import * as snabbdom from 'snabbdom';  import propsModule from 'snabbdom/modules/props';  ...  //QndReactDom 告訴 QndReact 如何更新 DOM  QndReact.__updater = () => {      //當調用 this.setState 的時候更新 DOM 邏輯  }

無論何時我們調用 this.setState({...}),我們都需要比較組件的 oldVNode 和在組件上調用了 render 方法之后生成的 newVNode。為了進行比較,我們在類組件上添加 __vNode 屬性,以維護該組件當前的 VNode 實例。

//src/qnd-react.js  ...  const createElement = (type, props = {}, ...children) => {      /**       * 如果是類組件       * 1.創建一個實例       * 2.調用實例的 render 方法       */      if (type.prototype && type.prototype.isQndReactClassComponent) {          const componentInstance = new type(props);          componentInstancecomponentInstance.__vNode = componentInstance.render();          return componentInstance.__vNode;      }      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };  ...

現在我們來在 Component 的基類中實現 setState 方法。

//src/qnd-react.js  ...  class Component {      constructor() { }      componentDidMount() { }      setState(partialState) {           this.state = {              ...this.state,              ...partialState          }          //調用 QndReactDom 提供的 __updater 方法          QndReact.__updater(this);      }      render() { }  }  ...

處理 QndReactDom 中的 __updater 方法。

//src/qnd-react-dom.js  ...  QndReact.__updater = (componentInstance) => {      //當調用 this.setState 的時候更新 DOM 邏輯      //獲取在 __vNode 上存儲的 oldVNode      const oldVNode = componentInstance.__vNode;      //獲取 newVNode      const newVNode = componentInstance.render();      //更新 __vNode      componentInstance.__vNode = reconcile(oldVNode, newVNode);  }  ...  export default QndReactDom;

OK,我們在 Counter 組件中增加 state 來檢驗我們的 setState 實現是否生效。

//src/counter.js  import QndReact from './qnd-react';  export default class Counter extends QndReact.Component {      constructor(props) {          super(props);          this.state = {              count: 0          }          // update the count every second          setInterval(() => {              this.setState({                  count: this.state.count + 1              })          }, 1000);      }      componentDidMount() {          console.log('Component mounted');      }      render() {          return <p>Count: {this.state.count}</p>      }  }

太棒啦,現在 Counter 組件運行情況與我們預期完全一致。

我們繼續添加 componentDidMount 的生命周期鉤子函數。 Snabbdom 提供了一些鉤子函數,通過他們,我們可以知道真實DOM上面是否有添加,刪除或是更新了虛擬DOM節點,你可以在此處了解更多信息。

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      /**       * 如果是類組件       * 1.創建一個實例       * 2.調用實例的 render 方法       */      if (type.prototype && type.prototype.isQndReactClassComponent) {          const componentInstance = new type(props);          componentInstancecomponentInstance.__vNode = componentInstance.render();          return componentInstance.__vNode;          //增加鉤子函數(當虛擬DOM被添加到真實DOM節點上時)          componentInstance.__vNode.data.hook = {              create: () => {                  componentInstance.componentDidMount()              }          }      }      //如果是函數組件,那么調用它,并返回執行結果      if (typeof (type) == 'function') {          return type(props);      }      return h(type, { props }, children);  };  ...  export default QndReact;

至此,我們已經在類組件上支持了 componentDidMount 生命周期鉤子函數。

結束之前,我們再添加下事件綁定的支持。為此,我們可以在 Counter 組件中增加一個按鈕,點擊的時候,計數器的數字增加。請注意,我們遵循的是基于常規的JS事件命名約定,而非基于 React,即雙擊事件使用 onDblClick,而非 onDoubleClick。

import QndReact from './qnd-react';  export default class Counter extends QndReact.Component {      constructor(props) {          super(props);          this.state = {              count: 0          }      }      componentDidMount() {          console.log('Component mounted');      }      render() {          return (              <div>                  <p>Count: {this.state.count}</p>                  <button onClick={() => this.setState({                      count: this.state.count + 1                  })}>Increment</button>              </div>          )      }  }

上面的組件不會正常工作,因為我們沒有告訴我們的 VDom 如何去處理它。首先,我們給 Snabdom 增加事件監聽模塊。

//src/qnd-react-dom.js  import QndReact from './qnd-react';  import * as snabbdom from 'snabbdom';  import propsModule from 'snabbdom/modules/props';  import eventlistenersModule from 'snabbdom/modules/eventlisteners';  const reconcile = snabbdom.init([propsModule, eventlistenersModule]);  ...

Snabdom 希望將文本屬性和事件屬性作為兩個單獨的對象,我們我們需要這樣做:

//src/qnd-react.js  import { h } from 'snabbdom';  const createElement = (type, props = {}, ...children) => {      ...      let dataProps = {};      let eventProps = {};      for (let propKey in props) {          // event 屬性總是以 `on` 開頭          if (propKey.startsWith('on')) {              const event = propKey.substring(2).toLowerCase();              eventProps[event] = props[propKey];          } else {              dataProps[propKey] = props[propKey];          }      }      return h(type, { props: dataProps, on: eventProps }, children);  };  ...

現在當我們點擊 Counter 組件的按鈕的時候,計數器加1。

怎么用JS代碼構建React

感謝各位的閱讀,以上就是“怎么用JS代碼構建React”的內容了,經過本文的學習后,相信大家對怎么用JS代碼構建React這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

合川市| 东乡| 通化市| 新绛县| 岢岚县| 内黄县| 鄯善县| 甘南县| 辽源市| 珠海市| 南江县| 台安县| 读书| 肇庆市| 襄城县| 远安县| 新巴尔虎右旗| 临潭县| 洪湖市| 铜鼓县| 阳信县| 基隆市| 加查县| 原平市| 荆门市| 漯河市| 青海省| 广东省| 万全县| 博白县| 金塔县| 恭城| 柘荣县| 新乡市| 新龙县| 龙江县| 平舆县| 闽侯县| 芒康县| 抚远县| 娄烦县|