1.Expanding Cards
效果如圖所示:
學到了什麼?
- React的函式元件中建立資料通訊,我們通常使用
useState
方法。它的使用方式採用陣列解構的方式,如下:
const [state,setState] = React.useState(false);//useState方法的引數可以是任意的JavaScript資料型別
解構的第一個引數是我們定義並且訪問的資料狀態,第二個引數則是當我們需要變動資料狀態時所呼叫的方法,其作用類似類元件中的this.setState
。
更詳細的使用方式參考文件 useState API。
2.與類元件類似的鉤子函式,或者也可以理解為是函式元件的生命週期useEffect
。它接收一個副作用函式effect
作為引數,如下所示:
useEffect(() => {});//裡面的箭頭函式即副作用函式
以上示例只是做了一個簡單的更換文件標題,事實上在這個副作用函式中,我們可以做很多事情,詳情參考文件 useEffect API。
3.React內部有自己的一套事件機制,我們稱之為合成事件。它與正常的JavaScript
繫結事件很類似,但是它將事件命名方式採用了駝峰式寫法,並且它也對事件物件做了一層包裝,其名為SyntheticEvent
。注意,這是一種跨瀏覽器端的包裝器,我們如果想要使用原生的事件物件,可以使用nativeEvent
屬性,這在後面的示例中可能會涉及到。比如我們以上的事件繫結:
onClick={ onChangeHandler.bind(this,index) }
注意這裡,我們通常需要呼叫bind
方法來將this
繫結到該元件例項上,為什麼要使用bind
方法來繫結this
呢,這是因為繫結事件的回撥函式(如這裡的:onChangeHandler
),它是作為一箇中間變數的,在呼叫該回撥函式的時候this
指向會丟失,所以需要顯示的繫結this
,這也是受JavaScript
自身特性所限制的。詳情可參考React繫結this的原因中的解釋。與之類似的是在類元件中繫結合成事件,我們也一樣需要顯示的繫結this
指向。
4.map
方法的原理。map
方法迭代一個陣列,然後根據返回值來對陣列項做處理,並返回處理後的陣列,請注意該方法不會改變原陣列。比如:
[1,2,3].map(i => i <= 1);//返回[1]
jsx
中渲染列表也正是利用了map
方法的這一特性,並且我們需要注意的是渲染列表的時候必須要指定一個key
,這是為了方便DIFF
演算法更好的比對虛擬DOM。
5.React中給標籤新增類名,我們是寫成className
的,這是因為class
被JavaScript
當做關鍵字。而如果我們需要動態繫結類名,可以看到,我們使用了模板字串,在這裡更像是寫JavaScript,比如我們可以利用三元表示式做判斷。
6.React中給標籤繫結style樣式,我們通常可以繫結一個物件,在React中,我們繫結動態資料就是寫一對{}
花括號,然後style裡面的樣式我們通常宣告成物件來表示,比如:
{
background:"#fff"
}
這代表它是一個樣式物件,然後React會在內部去將樣式物件轉換成樣式字串,然後新增到DOM的style物件中。
2.Progress Steps
效果如圖所示:
學到了什麼?
與第一個示例所用到的知識點很類似,相關的不必做說明。接下來我們來看不一樣的。
- 父元件向子元件傳遞資料,我們通常都是使用
props
。可以看到以上的示例,我們暴露了4個props,即:
width
stepItems
currentActive
onClickItem
width就是設定步驟條的容器寬度,這個沒什麼可說的,stepItems就是步驟條的子元件,是一個陣列,也可以在陣列項中寫jsx。而currentActive
則是傳入的當前是哪一步,是一個索引值,通常應該是數值。至於onClickItem
則是子元件暴露給父元件的方法。
- 類元件的生命週期。在這個類元件當中,我們使用到了
constructor,componentDidMount,render
的生命週期鉤子函式。我們可以根據語義來推測,當一個類元件被初始化時所經歷的生命週期鉤子函式執行順序一定是constructor => render => componentDidMount
。從語義上來將constructor
是一個建構函式,用於初始化狀態,然後初始化完成之後,我們就會渲染元件,然後才是準備掛載元件。
額外的,我們擴充套件一下,根據文件說明,我們可以知道詳細的生命週期。React元件生命週期包含3個階段:
掛載 => 更新 => 解除安裝
在元件掛載之前執行的有:
constructor => static getDerivedStateFromProps => render => componentWillMount(即將過時) => componentDidMount
在元件state變更之後,也就是更新之後,執行的有:
static getDerivedStateFromProps => shouldComponentUpdate => render => getSnapshotBeforeUpdate => componentWillReceiveProps(即將過時) => componentWillUpdate(即將過時) => componentDidUpdate
在元件解除安裝之後,執行的有:
componentWillUnmount
另還有錯誤處理的生命週期,也就是在渲染過程,生命週期,或子元件的建構函式發生錯誤時,會執行的鉤子函式:
static getDerivedFromStateError => componentDidCatch
這裡面有些生命週期我們並沒有用到,有些則是幾乎涵蓋了我們後續的所有示例,所以我們一定要牢記元件的生命週期的順序。
但是就這個示例而言,我們學會的應該是如何封裝一個元件。
3.Rotating Navigation Animation
效果如圖所示:
學到了什麼?
一些相同同前面示例相同的知識點自不必說,我們來看不一樣的知識點。
1.模組組合匯出
//components目錄下的index.js檔案
export { default as Content } from './Content';
export { default as LeftMenu } from './LeftMenu';
export { default as NavList } from "./NavList";
可以看到,我們可以將元件如上面那樣匯出,然後我們就可以單獨引入一個js檔案,再引入相關的元件即可使用。如下:
import { Content, NavList, LeftMenu } from './components/index';
2.react元件如何渲染html字串
react提供了一個dangerouslySetInnerHTML
屬性,這個屬性的屬性值是一個以__html
作為屬性,值是html
字串的物件,然後,我們就可以將html
字串渲染成真實的DOM
元素。如下所示:
<p dangerouslySetInnerHTML={{ __html:"<span>測試程式碼</span>" }}></p>
//<p><span>測試程式碼</span></p>
4.hidden-search-widget
效果如圖所示:
學到了什麼?
本示例同樣的與前面的示例有一樣的知識點,相關的不會做說明,只會做不同的知識點介紹,後續的同理。
1.判斷資料的型別。利用物件原型鏈上的toString
方法,我們可以得到一個字串值,這個字串值的格式類似[object Object]
這樣,也就是說我們可以通過這個字串值來判斷一個資料的型別。例如:
const getType = v => Object.prototype.toString.call(v).slice(8,-1).toLowerCase();
const isArray = v => getType(v) === "array";
isArray([1,2,3]);//true
isArray("");//false
這裡我們應該知道Object.prototype.toString.call(v)
返回的就是類似[object Object]
這樣的值。所以我們通過擷取開始索引為8,結束索引為該字串長度減1,也就是這裡的-1,我們就可以獲取到第二個值Object
,然後再呼叫toLowerCase()
方法來將全部字母轉換成小寫,然後,我們就可以知道資料的型別了。比如這裡的判斷是否是陣列,那麼只需要判斷該值是否等於"array"即可。
2.React.createRef API
有時候,我們恰恰需要操作一些原生DOM元素的API,例如這個示例的輸入框的關注焦點事件。這時候這個API就有了用武之地,我們相當於使用這個API建立一個與DOM元素通訊的橋樑,通過這個訪問這個API的例項的current屬性,我們就可以訪問到相應的DOM元素。
更詳細的可以參考文件createRef API。
3.如何封裝一個input元件。
這個示例也教會了我們如何封裝一個input元件。
5.Blurry Loading
效果如圖所示:
學到了什麼?
- 在
componentDidMount
生命週期中建立定時器以及在componentWillUnmount
中清除定時器。 - 類元件中的
this.setState
更新狀態。該方法接收2個引數,第一個引數則是我們的react狀態,它可以是一個函式,也可以是一個物件。第二個引數則是一個回撥函式。談到這裡,可能就會提到一個問題,那就是setState到底是非同步還是同步? 答案如下:
答:react中的setState在合成事件和鉤子函式中是"非同步"的,而在原生事件和setTimeout中則是同步的。
之所以是"非同步",並不代表在react內部中是"非同步"程式碼實現的,事實上,它仍然是同步執行的一個過程。
只是合成事件和鉤子函式的呼叫順序在更新之前,導致在合成函式和鉤子函式中沒法立即拿到更新後的值,所以就形成了所謂的"非同步"。
事實上,我們可以通過制定第二個引數即callback(回撥函式)來獲取到更新後的值。
react.js對setState的原始碼實現也不是很複雜,它將傳入的引數作為值新增到updater
也就是更新器的一個定義好的佇列(即:enqueueSetState)中。
react中的批量更新優化也是建立在合成事件和鉤子函式(也就是"非同步")之上的,在原生事件和setTimeout中則不會進行批量更新。
比如在"非同步"中對同一個值進行多次setState,依據批量更新則會對其進行策略覆蓋,而如果是對不同的多個值setState,則會利用批量更新策略對其進行合併然後批量更新。
更詳細的可以參考文件 setState 。
除此之外,這裡也有一個非常重要的工具函式(這在js的實現中也提及過),如下所示:
const scale = (n,inMin,inMax,outerMin,outerMax) => (n - inMin) * (outerMax - outerMin) / (inMax - inMin) + outerMin;
這個工具函式的作用就是將一個範圍數字對映到另一個數字範圍。比方說,將1 ~ 100
的數字範圍對映到0 ~ 1
之間。
詳情。
6.Scroll Animation
效果如圖所示:
學到了什麼?
1.動態元件
我們通過props傳遞一個值用來確定元件名。這裡以Title
元件為例,如下所示:
import React from "react";
const TitleComponent = (props) => {
let TagName = `h${ props.level }`;
return (
<React.Fragment>
<TagName>{ props.children }</TagName>
</React.Fragment>
)
}
export default TitleComponent;
雖然核心程式碼十分簡單,這裡需要注意,React元件需要首字母大寫,這算是一個約定的規則,其次我們通過props傳遞一個level用來確定我們使用的是h1~h6
哪個來做標籤,事實上這裡我們應該對level做一個限制,只允許值為1~6
。
2.Fragment元素
這個元素類似於一個佔位符節點,我們知道,當兩個元素並列在一個React元件中,是不被允許的,React元件需要提供一個根節點,但有時候,我們不需要一個實際的元素作為根節點包裹它們,所以我們就可以使用Fragment
元素來包裹它們。該元素還有一個簡寫<></>
,事實上在Vue2.x中也有這個限制,這是受虛擬DOM DIFF演算法所限制的。
更詳細的可以見文件Fragment。
3.函式防抖
export const throttle = (fn, time = 1000) => {
let done = false;
return (...args) => {
if (!done) {
fn.call(this, ...args);
done = true;
}
setTimeout(() => {
done = false;
}, time)
}
}
函式防抖與節流可參考 這篇文章 。
4.監聽滾動事件,事實上這裡的實現原理同JavaScript實現版本一致,只不過稍微轉換一下思維即可。
7. Split Landing Page
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
8.Form Wave
效果如圖所示:
學到了什麼?
- setState更新物件,如果state是一個物件,我們有2種方式來更新。
1.1 利用Object.assign方法來更新。
1.2 直接覆蓋整個物件。
以上2種方式虛擬碼如下:
// 第1種方式
const loginInfo = Object.assign({},this.state.loginInfo,{
[key]:updateValue
})
this.setState({
loginInfo
});
// 第2種方式
let { loginInfo } = this.state;
loginInfo[key] = updateValue;
this.setState({ loginInfo });
9.Sound Board
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
10. Dad Jokes
效果如圖所示:
學到了什麼?
- Suspense元件的使用。該元件可以指定一個載入指示器元件,用來實現元件的懶載入。更詳細的文件見 Suspense 。
- 介面請求通常都是在componentDidMount鉤子函式中完成的。由於不能直接在該鉤子函式中更改狀態(react.js會給出一個警告)。所以我們需要讓介面請求變成非同步。
11. Event Keycodes
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
12. Faq Collapse
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
13. Random Choice Picker
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
14. Animated Navigation
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
15. Incrementing Counter
效果如圖所示:
學到了什麼?
- react.js如何更新陣列的某一項?在這裡我是更新整個陣列的,或許這不是一種好的方式。也希望有大佬能提供思路。我的程式碼如下:
startCounter() {
const counterList = [...this.state.counterList];
// https://stackoverflow.com/questions/29537299/react-how-to-update-state-item1-in-state-using-setstate
// https://stackoverflow.com/questions/26253351/correct-modification-of-state-arrays-in-react-js
counterList.forEach(counter => {
const updateCounter = () => {
const value = counter.value;
const increment = value / 100;
if (counter.initValue < value) {
counter.initValue = Math.ceil(counter.initValue + increment);
// use setTimeout or setInterval ?
counter.timer = setTimeout(updateCounter, 60);
} else {
counter.initValue = value;
clearTimeout(counter.timer);
}
// update the array,maybe it's not a best way,is there any other way?
this.setState({ counterList });
}
updateCounter();
})
}
16. Drink Water
效果如圖所示:
學到了什麼?
- 這裡踩了一個坑,如果使用new Array().fill()來初始化狀態,會導致意想不到的渲染效果。所以這裡直接初始化了所有的陣列項。
詳見原始碼 。
17. movie-app
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
PS:這個示例效果由於介面訪問受限,需要你懂的訪問。
18. background-slider
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
19. theme-clock
效果如圖所示:
學到了什麼?
- 中英文切換是通過定義一個物件來完成的。其它的沒什麼好說的,都是前面提及過的知識點。
PS:本示例也用到了與示例5一樣的工具函式scale
函式
20. button-ripple-effect
效果如圖所示:
學到了什麼?
- 可以通過呼叫函式來渲染一個元件。
21. drawing-app
效果如圖所示:
學到了什麼?
- 在react.js中使用
ew-color-picker
。 - 這裡踩了一個坑,也就是說必須要設定線條的樣式。
this.ctx.lineCap = "round";
否則線條的樣式不對勁,雖然我也沒有搞清楚這裡面的原因。畢竟js版本的實現也沒有需要顯示的設定這個線條的樣式。
22. drag-n-drop
效果如圖所示:
學到了什麼?
- 這裡也踩了一個坑, 詳見原始碼註釋 。
23. content-placeholder
效果如圖所示:
學到了什麼?
- 一些判斷react元件的工具函式。如下:
import React from "react";
export function isString(value){
return typeof value === "string";
}
export function isClassComponent(component) {
return typeof component === 'function' && !!component.prototype.isReactComponent;
}
export function isFunctionComponent(component) {
return typeof component === 'function' && String(component).indexOf('return React.createElement') > -1;
}
export function isReactComponent(component) {
return isClassComponent(component) || isFunctionComponent(component);
}
export function isElement(element) {
return React.isValidElement(element);
}
export function isDOMTypeElement(element) {
return isElement(element) && typeof element.type === 'string';
}
export function isCompositeTypeElement(element) {
return isElement(element) && typeof element.type === 'function';
}
- 如何封裝一個卡片元件。
24. kinetic-loader
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點前面的示例都提及過,所以這裡不必贅述。
25. sticky-navbar
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點除了一個工具函式,其它的知識點前面的示例都提及過,所以這裡不必贅述。
export function marked(template){
return template.replace(/.+?[\s]/g,v => `<p>${v}</p>`);
}
這個工具函式的作用就是匹配以空格結束的任意字元,然後替換成p標籤包裹這些內容。
PS:這裡也做了移動端的佈局。
26. double-slider
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
27. toast-notification
效果如圖所示:
學到了什麼?
- 可以利用
ReactDOM.render
來封裝一個函式呼叫的toast
元件。 ReactDOM.unmountComponentAtNode API
的用法這個方法會將從DOM中解除安裝元件,包括事件處理器和state。詳見 文件 。- getDerivedStateFromProps 靜態函式。詳見 文件。
28. github-profiles
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
29. double-click-heart
效果如圖所示:
學到了什麼?
- 從合成事件物件中讀取原生的事件物件。即
nativeEvent
屬性。
30. auto-text-effect
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
31. password generator
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
32. good-cheap-fast
效果如圖所示:
學到了什麼?
- 如何封裝一個switch元件,即開關小元件。
33. notes-app
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
34. animated-countdown
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
35. image-carousel
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
36. hover board
效果如圖所示:
學到了什麼?
- react.js合成事件中的setState是同步的,所以這裡使用原生的監聽事件來實現。 詳見原始碼 。
37. pokedex
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
38. mobile-tab-navigation
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
39. password-strength-background
效果如圖所示:
學到了什麼?
- 照著 文件 一步步將
tailwindcss
新增到create-react-app
腳手架中。
40. 3D-background-boxes
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
41. Verify Your Account
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
42. live-user-filter
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
43. feedback-ui-design
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
44. custom-range-slider
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
45. netflix-mobile-navigation
效果如圖所示:
學到了什麼?
- 為如何實現一個遞迴元件提供了思路。
46. quiz-app
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
47. testimonial-box-switcher
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
48. random-image-feed
效果如圖所示:
學到了什麼?
- 實現一個簡易版本的預覽圖片。
49. todo-list
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
50. insect-catch-game
效果如圖所示:
學到了什麼?
這個示例涉及到的知識點,前面的示例都提及過,所以這裡不必贅述。
特別說明:這個示例算是一個比較綜合的示例了。