項目地址:reduxjs/reselectjavascript
輪子做用:減小沒必要要的數據計算。java
適用場景:從redux store中取數據的時候。react
在一個大型的項目中,咱們會在store中保存不少數據,同時也會有不少的大小組件。不一樣的組件須要不一樣的數據,因此咱們保存在store中的數據每每是很完整和龐大的,在存進store以前都不會對從服務器請求回來的數據進行過多處理。git
而咱們每個組件所須要的數據可能都是不一樣的,因此咱們須要把store中的數據處理成組件所須要的數據。在這個過程當中,咱們可能須要遍歷不少對象與數組,而這些計算在每次刷新的時候都須要進行一遍,哪怕觸發刷新的是別的徹底無關的操做。github
reselect就是爲了不過多沒必要要的運算而誕生的輪子,它會緩存上次輸入與輸出,當它再次執行的時候會先檢查一下函數的輸入,若是與上次相同則避免計算,直接用上次的結果輸出。redux
reselect還能夠嵌套地寫,來把一個數據變化的過程拆分紅不少子過程,這些子過程也能夠被別的reselect函數複用。並且任何一級的輸入不變則後續的過程都會使用緩存輸出。數組
以一個例子說明,假如個人state中有以下的數據:緩存
state = {
students: [
{
name: 'tom',
age: 12,
},
{
name: 'mike',
age: 13,
},
]
}
複製代碼
我有一個組件須要用到全部學生的名單,那麼reselect的寫法以下:服務器
import { createSelector } from 'reselect'
// 從state中拿出學生數據
const studentsSelector = state => state.students
// createSelector的全部參數都是函數
// 前面的函數擁有相同的輸入,好比都是state
// 最後一個函數的輸入是前面全部函數的輸出
// 最後一個函數的輸出就是reselect函數的輸出
const nameListSelector = createSelector(
studentsSelector,
students => students.map(student => student.name)
)
nameList = nameListSelector(state) // ['tom', 'mike']
複製代碼
同時我還有一個組件要用到全部學生年齡的清單,那麼咱們只須要寫:函數
const ageListSelector = createSelector(
studentsSelector,
students => students.map(student => student.age)
)
ageList = ageListSelector(state) // [12, 13]
複製代碼
咱們複用了前面的studentsSelector函數,讓代碼獲得了簡化。須要注意studentsSelector並非一個reselect函數,因此不具有緩存輸入輸出的能力。
後面的nameListSelector與ageListSelector則是正統的reselect函數,能夠在輸入相同的狀況下跳過計算,直接給出緩存的結果。這樣寫的好處會在下面的場景中顯現:
students.map(student => student.name)
的函數都會返回新的結果,由於map方法的特性就是會返回新的數組,從而觸發後續內容都的從新渲染,即便先後的map方法返回的實際內容同樣,由於數組的引用變化了,因此react就會認爲它變了。使用reselect函數能夠很方便地完成從store數據到組件輸入的轉換,能夠在各類從新渲染的時候避免沒必要要的計算從而提高性能。更加由於其複用的特性,減小了重複代碼的書寫,稱得上是即高效又優雅。