摘要:無(wú)狀態(tài)組件除了可以通過(guò)來(lái)創(chuàng)建組件以外,組件也可以通過(guò)一個(gè)普通的函數(shù)定義,函數(shù)的返回值為組件渲染的結(jié)果。這就是為什么要有屬性,屬性能夠幫助定位與數(shù)組元素的關(guān)系,在重渲染的時(shí)候能夠?qū)崿F(xiàn)渲染優(yōu)化。
1.3 React 組件 1.3.1 React 組件介紹書籍完整目錄
在 React 中組件是第一元素,是 React 的基礎(chǔ),一個(gè) React 應(yīng)用就是基于 React 組件的組合而成。
前面的 JSX 練習(xí)過(guò)后,大家應(yīng)該對(duì) React 組件不陌生了,在這一節(jié)我們將溫習(xí)以及深入學(xué)習(xí) React 組件。
創(chuàng)建一個(gè) React 組件的方法為,調(diào)用 React.createClass 方法,傳入的參數(shù)為一個(gè)對(duì)象,對(duì)象必須定義一個(gè) render 方法,render 方法返回值為組件的渲染結(jié)構(gòu),也可以理解為一個(gè)組件實(shí)例(React.createElement 工廠方法的返回值),返回值有且只能為一個(gè)組件實(shí)例,或者返回 null/false,當(dāng)返回值為 null/false 的時(shí)候,React 內(nèi)部通過(guò) 標(biāo)簽替換。
eg:
var MyComponent = React.createClass({ render: function() { return組件命名空間....
; } });
可以看出 React.createClass 生成的組件類為一個(gè) Javascript 對(duì)象。 當(dāng)我們想設(shè)置命名空間組件時(shí),可以在組件下面添加子組件:
eg:
MyComponent.SubComponent = React.createClass({...}); MyComponent.SubComponent.Sub = React.createClass({....});
在組件較多的情況下,可以借助命名空間優(yōu)化組件維護(hù)結(jié)構(gòu)以及解決組件名稱沖突問(wèn)題。
無(wú)狀態(tài)組件除了可以通過(guò) React.createClass 來(lái)創(chuàng)建組件以外,組件也可以通過(guò)一個(gè)普通的函數(shù)定義,函數(shù)的返回值為組件渲染的結(jié)果。
eg:
function StatelessComponent(props) { returnHello {props.name}}
無(wú)狀態(tài)組件能夠優(yōu)化性能,因?yàn)槠鋬?nèi)部不會(huì)維護(hù)狀態(tài),React 內(nèi)部不會(huì)有一個(gè)對(duì)應(yīng)的組件實(shí)例,并且也沒(méi)有生命周期 hook。
1.3.3 將組件渲染到 DOM 中當(dāng)創(chuàng)建好了組件過(guò)后,為了將組件渲染到 DOM 中顯示出來(lái),需要兩個(gè)步驟
在 HTML 中定義一個(gè)元素,設(shè)置 id 屬性
JSX 中調(diào)用 ReactDOM.render 方法, 第一個(gè)參數(shù)為 組件,第二個(gè)為剛才定義的 DOM 元素
eg:
對(duì)于組件的渲染,可能涉及到的一些問(wèn)題:
Q1: 只能 render 到一個(gè)元素嗎?
Q2: 在程序運(yùn)行時(shí)能夠動(dòng)態(tài)的調(diào)用 render 嗎?
Q3: 修改了數(shù)據(jù)過(guò)后,還需要重新調(diào)用 render 方法嗎?
這里要先提一下 React 的設(shè)計(jì)初衷,React 在開(kāi)發(fā)時(shí)候的目標(biāo)就是簡(jiǎn)單精巧,可以和其他框架結(jié)合起來(lái)使用。簡(jiǎn)單而言我們可以當(dāng) React 是一個(gè)渲染數(shù)據(jù)對(duì)象到 DOM 中的 Javascript 函數(shù)工具類,工具類當(dāng)然可以多次使用。
那么對(duì)于上面的問(wèn)題:
A1: 不是,React 可以渲染到多個(gè)元素,任意位置的元素。
A2: 可以,比如以一個(gè)彈出層組件為例,我們希望創(chuàng)建一個(gè) append 到 body 最后的組件來(lái)實(shí)現(xiàn)全屏遮罩, 那么我們可以動(dòng)態(tài)的創(chuàng)建一個(gè) div append 到 body 最后,然后將彈出層 render 到那個(gè) div 內(nèi)。
A3: 假設(shè)每次數(shù)據(jù)改變都重新調(diào)用 render 方法,那么每次 render 帶來(lái)的結(jié)果是重新創(chuàng)建一個(gè)頂級(jí)組件實(shí)例,以及子組件實(shí)例。 如果只調(diào)用 render 一次,將數(shù)據(jù)的變更放在組件內(nèi)部,那么就不會(huì)重復(fù)創(chuàng)建頂級(jí)組件。
1.3.4 組件狀態(tài) StateReact 中每個(gè)組件可以存儲(chǔ)自己的當(dāng)前狀態(tài), 以一個(gè) switch 開(kāi)關(guān)組件為例,開(kāi)關(guān)的狀態(tài)可以存儲(chǔ)在組件內(nèi)部。
React 的渲染結(jié)果是由組件屬性和狀態(tài)共同決定的,狀態(tài)和屬性的區(qū)別是,狀態(tài)維護(hù)在組件內(nèi)部,屬性是由外部控制,我們先介紹組件狀態(tài)相關(guān)細(xì)節(jié):
控制狀態(tài)的 API 為:
this.state:組件的當(dāng)前狀態(tài)
getInitialState:獲取組件的初始狀態(tài),在組件加載的時(shí)候會(huì)被調(diào)用一次,返回值賦予 this.state 作為初始值
this.setState:
組件狀態(tài)改變時(shí),可以通過(guò) this.setState 修改狀態(tài)
setState 方法支持按需修改,如 state 有兩個(gè)字段,僅當(dāng) setState 傳入的對(duì)象包含字段 key 才會(huì)修改屬性
每次調(diào)用 setState 會(huì)導(dǎo)致重渲染調(diào)用 render 方法
直接修改 state 不會(huì)重渲染組件
eg:
var Switch = React.createClass({ // 定義組件的初始狀態(tài),初始為關(guān) getInitialState: function() { return { open: false } }, // 通過(guò) this.state 獲取當(dāng)前狀態(tài) render: function() { console.log("render switch component"); var open = this.state.open; return }, // 通過(guò) setState 修改組件狀態(tài) // setState 過(guò)后會(huì) React 會(huì)調(diào)用 render 方法重渲染 toggleSwitch: function() { var open = this.state.open; this.setState({ open: !open }); } })1.3.5 組件屬性 Props
前面已經(jīng)提到過(guò) React 組件可以傳遞屬性給組件,傳遞方法和 HTML 中無(wú)異, 可以通過(guò) this.props 獲取組件屬性
屬性相關(guān)的 API 為:
this.props: 獲取屬性值
getDefaultProps: 獲取默認(rèn)屬性對(duì)象,會(huì)被調(diào)用一次,當(dāng)組件類創(chuàng)建的時(shí)候就會(huì)被調(diào)用,返回值會(huì)被緩存起來(lái),當(dāng)組件被實(shí)例化過(guò)后如果傳入的屬性沒(méi)有值,會(huì)返回默認(rèn)屬性值
this.props.children:子節(jié)點(diǎn)屬性
propTypes: 屬性類型檢查
以一個(gè)代辦事項(xiàng)的列表項(xiàng)組件為例:
// props.name 表示代辦事項(xiàng)的名稱 var TodoItem = React.createClass({ render: function() { var props = this.props; returnchildren 屬性{props.name}} }); ReactDOM.render(, document.getElementById("example"));
組件屬性中會(huì)有一個(gè)特殊屬性 children ,表示子組件, 還是以上面一個(gè)組件為例子,我們可以換一種方式定義 name:
var TodoItem = React.createClass({ render: function() { var props = this.props; return{props.children}} }); ReactDOM.render(代辦事項(xiàng)1 , document.getElementById("example"));
屬性類型檢查需要注意的是,children 只能為一個(gè)元素,不能為多個(gè)組件
為了保證組件傳遞屬性的正確性, 我們可以通過(guò)定義 propsType 對(duì)象來(lái)實(shí)現(xiàn)對(duì)組件屬性的嚴(yán)格校驗(yàn):
var MyComponent = React.createClass({ propTypes: { optionalArray: React.PropTypes.array, optionalBool: React.PropTypes.bool, optionalFunc: React.PropTypes.func, optionalNumber: React.PropTypes.number, optionalObject: React.PropTypes.object, optionalString: React.PropTypes.string, // 任何可以被渲染的包括,數(shù)字,字符串,組件,或者數(shù)組 optionalNode: React.PropTypes.node, // React 元素 optionalElement: React.PropTypes.element, // 枚舉 optionalEnum: React.PropTypes.oneOf(["News", "Photos"]), // 任意一種類型 optionalUnion: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, React.PropTypes.instanceOf(Message) ]), // 具體類型的數(shù)組 optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), // 具體類型的對(duì)象 optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), // 符合定義的對(duì)象 optionalObjectWithShape: React.PropTypes.shape({ color: React.PropTypes.string, fontSize: React.PropTypes.number }), requiredFunc: React.PropTypes.func.isRequired, requiredAny: React.PropTypes.any.isRequired, // 自定義校驗(yàn) customProp: function(props, propName, componentName) {} } });屬性傳遞的單向性
我們已經(jīng)提到過(guò) React 的單向數(shù)據(jù)流模式,數(shù)據(jù)的流動(dòng)管道就是 props,流動(dòng)的方向就是組件的層級(jí)自定向下的方向。所以一個(gè)組件是不能修改自身的屬性的,組件的屬性一定是通過(guò)父組件傳遞而來(lái)(或者默認(rèn)屬性)。
無(wú)狀態(tài)組件屬性對(duì)于無(wú)狀態(tài)組件,可以添加 .propTypes 和 .defaultProps 屬性到函數(shù)上。
1.3.6 組件的嵌套組合在 1.2 節(jié)的 JSX 實(shí)例子中,當(dāng)我們循環(huán)輸出 todo 列表的時(shí)候,React 會(huì)提示對(duì)于循環(huán)輸出的組件,需要有一個(gè)唯一的 key 屬性。這個(gè)問(wèn)題的原因在于 React 的調(diào)和機(jī)制(Reconciliation)上。
什么叫調(diào)和?在每次數(shù)據(jù)更新過(guò)后,React 會(huì)重新調(diào)用 render 渲染出新的組件結(jié)構(gòu),新的結(jié)構(gòu)應(yīng)用到 DOM 中的過(guò)程就叫做調(diào)和過(guò)程。
為什么需要調(diào)和?想一想,假設(shè)我們有一個(gè)輸入組件,這個(gè)時(shí)候我們正聚焦在輸入框中,當(dāng)修改值過(guò)后觸發(fā)事件導(dǎo)致了數(shù)據(jù)改變,數(shù)據(jù)改變導(dǎo)致了重渲染, 這個(gè)時(shí)候輸入框被替換成了新的 DOM。 這個(gè)過(guò)程對(duì)用戶來(lái)說(shuō)應(yīng)該是無(wú)感知的,所以那原來(lái)的聚焦?fàn)顟B(tài)應(yīng)該被保存, 那怎么做到的呢? DOM 都被替換了,輸入狀態(tài),選擇狀態(tài)為什么還能保存。 我們先不急著知道 How,目前只需要知道這就是調(diào)和過(guò)程,后面我們會(huì)在 React 實(shí)現(xiàn)原理章節(jié)進(jìn)行詳細(xì)介紹。
除了保存狀態(tài)以外,調(diào)和過(guò)程還做了很多 DOM 優(yōu)化。 比如輸出一個(gè)數(shù)組的時(shí)候,數(shù)據(jù)新增加或者減少了一下,或者數(shù)組項(xiàng)值改變了,實(shí)際上我們沒(méi)有必要?jiǎng)h除原來(lái)的 DOM 結(jié)構(gòu),只需要修改 DOM 的值或者刪除 DOM 就能實(shí)現(xiàn)重渲染。
這就是為什么要有 key 屬性,key 屬性能夠幫助定位 DOM 與數(shù)組元素的關(guān)系,在重渲染的時(shí)候能夠?qū)崿F(xiàn)渲染優(yōu)化。
1.3.7 實(shí)例練習(xí):通過(guò)組件化的方式優(yōu)化之前的待辦事項(xiàng)列表 問(wèn)題優(yōu)化 JSX 語(yǔ)法練習(xí)的 TODOMVC 頁(yè)面, 通過(guò)組件化的方式拆分頁(yè)面!
組件如下:
App 組件:整個(gè)頁(yè)面的最完成組件
Header 組件:頭部輸入組件
TodoList 組件:列表組件
TodoItem 組件: 列表項(xiàng)
Footer 組件:底部操作組件
Tips循環(huán)輸出組件的方式
方式一:先計(jì)算出組件
function render() { var todos = this.props.todos; var $todos = todos.map(function(todo) { return}); return {$todos}}
方式二:{} 內(nèi)直接計(jì)算
function render() { var todos = this.props.todos; return參考答案{todos.map(function(todo) { return}})}
https://github.com/leanklass/leanreact/tree/component
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/79489.html
摘要:無(wú)狀態(tài)組件除了可以通過(guò)來(lái)創(chuàng)建組件以外,組件也可以通過(guò)一個(gè)普通的函數(shù)定義,函數(shù)的返回值為組件渲染的結(jié)果。這就是為什么要有屬性,屬性能夠幫助定位與數(shù)組元素的關(guān)系,在重渲染的時(shí)候能夠?qū)崿F(xiàn)渲染優(yōu)化。 書籍完整目錄 1.3 React 組件 showImg(https://segmentfault.com/img/bVvLOW); 1.3.1 React 組件介紹 在 React 中組件是第一元...
書籍完整目錄 4.1 react 代碼規(guī)范 showImg(https://segmentfault.com/img/bVyE9m); 關(guān)于 基礎(chǔ)規(guī)范 組件結(jié)構(gòu) 命名規(guī)范 jsx 書寫規(guī)范 eslint-plugin-react 關(guān)于 在代碼的設(shè)計(jì)上,每個(gè)團(tuán)隊(duì)可能都有一定的代碼規(guī)范和模式,好的代碼規(guī)范能夠提高代碼的可讀性便于協(xié)作溝通,好的模式能夠上層設(shè)計(jì)上避免不必要的 bug 出現(xiàn)。本節(jié)會(huì)參考...
摘要:需要提醒讀者的是,的很多例子都是通過(guò)來(lái)寫的,但這并不是語(yǔ)法,后面我們會(huì)有單獨(dú)的一小節(jié)講解的基本語(yǔ)法,不過(guò)目前為止我們先將跟多精力放在上。 書籍完整目錄 1.2 JSX 語(yǔ)法 showImg(https://segmentfault.com/img/bVvKLR); 官方文檔 https://facebook.github.io/react/docs/jsx-in-depth.html ...
摘要:?jiǎn)蜗驍?shù)據(jù)流應(yīng)用的核心設(shè)計(jì)模式,數(shù)據(jù)流向自頂向下我也是性子急的人,按照技術(shù)界的慣例,在學(xué)習(xí)一個(gè)技術(shù)前,首先得說(shuō)一句。然而的單向數(shù)據(jù)流的設(shè)計(jì)讓前端定位變得簡(jiǎn)單,頁(yè)面的和數(shù)據(jù)的對(duì)應(yīng)是唯一的我們可以通過(guò)定位數(shù)據(jù)變化就可以定位頁(yè)面展現(xiàn)問(wèn)題。 書籍完整目錄 1.1 React 介紹 showImg(https://segmentfault.com/img/bVvJgS); 1.1.1 React ...
閱讀 3799·2023-01-11 11:02
閱讀 4305·2023-01-11 11:02
閱讀 3127·2023-01-11 11:02
閱讀 5237·2023-01-11 11:02
閱讀 4800·2023-01-11 11:02
閱讀 5573·2023-01-11 11:02
閱讀 5378·2023-01-11 11:02
閱讀 4079·2023-01-11 11:02