2-6
useSelector
const post = useSelector(state => state.user.posts.find(post => post.id === id)))
// state.user 的 user 為該 slice 的名稱,slice 為 Redux 官方定義用來區別不同的 store 資料
useSelector(func)
,傳入一個 callback fuction,callback fuction 會取得的第一個參數是 state,用來取得 store 裡的資料。- 每次有 action disaptched 時,
useSelector
都會重新執行一遍 (就算是不同的 slice 都會) - 若應用越來越大,每次有 action disaptched 時想必會讓各處很多的
useSelector
重新計算,故可以用createSelector
來建立一個 memoized selector
createSelector
// 建立 memoized selector
const selectPostsByUser = createSelector(
[selectAllPosts, (state, userId) => userId],
(posts, userId) => posts.filter(post => post.user === userId)
)
// 組件內使用
const postsForUser = useSelector(state => selectPostsByUser(state, userId))
- createSelector 第一個參數為陣列,陣列內需為 function,稱為 input selector,call selectPostsByUser 時所傳入的參數,會傳入每個 input selector ,意指每個 input selector 取得的參數都一樣,接著根據每個 input selector 得出的值,會傳入 createSelector 的第二個參數 output selector function 內,output selector 取得 input selector 得出的值做運算並回傳結果。
- 此 memoized 重點在於呼叫
selectPostsByUser
時傳入的值前後是否一樣,或是 input selector 回傳的值前後是否一樣,若都相同則useSelector
會回傳上次的計算結果。 - 上述再補充:呼叫
selectPostsByUser
時傳入的值若前後不一樣則會跑 input selector, input selector 回傳的值若前後不一樣則會跑 output selector。其中某個階段的結果值前後一樣就會回傳上次最終的計算結果。
shallowEqual
import { shallowEqual, useSelector } from 'react-redux'
// later
const selectedData = useSelector(selectorReturningObject, shallowEqual)
useSelector
可傳入第二個參數,shallowEqual
用於比對 selectorReturningObject 回傳的值是否淺相等,經常使用在 若 selector 計算過後會回傳新的 reference 物件,由於前後值一定不一樣故 selectedData 一定會變,此shallowEqual
就是只淺比對回傳的物件前後是否一樣 (不看reference),若一樣則回傳上次的舊的 reference 物件。
craco
- Create React App Configuration Override,使用 create react app 建立專案後,若是要自訂 webpack 相關配置,則可以安裝 @craco/craco,並在根目錄新增
craco.config.js
即可在裡面寫配置。 - 並在
package.json
改成使用 craco 指令。
/* package.json */
"scripts": {
// "start": "react-scripts start",
"start": "craco start",
// "build": "react-scripts build",
"build": "craco build",
// "test": "react-scripts test",
"test": "craco test"
}
@ path alias in React
/* craco.config.js */
module.exports = {
webpack: {
alias: {
'@': path.resolve(__dirname, 'src/'),
'@components': path.resolve(__dirname, 'src/components/'),
'@images': path.resolve(__dirname, 'src/assets/images/'),
'@styles': path.resolve(__dirname, 'src/styles/')
}
}
}
- 方便在引入常用的資料夾檔案
git revert -m
- 情況:merge 後想 revert,這時需要給 m 參數,決定要回到哪一個 branch 的 commit 點,回到自己的 branch 給 1,反之給 2。
- https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_reverse_commit
git 修改 commit 訊息
git commit —amend
,修改最近提交的一次 commit 訊息。git push --force-with-lease <遠端儲存庫別名> <分支名稱>
,將更改推送到遠端儲存庫。- --force-with-lease 可避免執行時,若有其他人在對遠端儲存庫存取,對資料造成損毀。
Jest
- toBe 是用 Object.is 檢查是否相等(包含參考),toEqual 是檢查值是否相等(不檢查參考)。
test.only
可以讓該檔案只跑該 test,在 trace test failed 原因時很有用。
Jest Asynchronous Code
測試非同步的函式有三種方式,callback、Promise.then().catch、async await。 個人較常與偏好使用 async await 故擷取該範例:
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
// 使用此語法給定這個 test 預計要有幾個 expect 執行,若沒有這個,fetchData fullfilled 時將會通過測試
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
- 使用 callback 或其他需要等待的測試時,給 test 的 callback function 可以接 done 的參數,可用來在完成時呼叫
done()
- 接 done 的參數卻沒有使用時,預設是等5秒後會 failed test
- 測試 Promise.then().catch 非同步函式時,需要 return 該 Promise
Jest Setup and Teardown
在一些情境下,需要在跑該測試前先建立一些資料等等,可以用下列方法建立:
- 在每個 test 前都做一次
beforeEach(() => {
initializeCityDatabase();
});
afterEach(() => {
clearCityDatabase();
});
- 在該檔案內跑 test 前,做一次
beforeAll(() => {
return initializeCityDatabase();
});
afterAll(() => {
return clearCityDatabase();
});
Scoping
- 使用
describe
function 將test
包含在內,形成一個 scope,在此describe
內的 before & after 系列都只會作用在此範圍內。 - top-level 的 before 會優先執行,after 會最後執行。
describe
會全部都跑過一次,才會跑test
。
it & test
- 根據官方文檔:這兩個函式用法相同,it 是 test 的 alias。
- https://jestjs.io/docs/api#testname-fn-timeout
bash
- bash v4 以後才有
declare -a
參數可以用 - 查詢版本:
bash —version
declare [-afFirtx] [-p] [name[=value] ...]
encodeURIComponent()
- 將字串轉換成 UTF-8 編碼
console.log(`${encodeURIComponent('?=/&;')}`)
console.log(`${encodeURIComponent('哈囉')}`)
`// "%3F%3D%2F%26%3B"
// "%E5%93%88%E5%9B%89"`
- 不轉換符號包括:A-Z a-z 0-9 - _ . ! ~ * ' ( )
decodeURIComponent()
- 和
encodeURIComponent()
相反
encodeURI()
- 將字串轉換成 UTF-8 編碼
- 一般情況下最好使用
encodeURIComponent()
encodeURI()
產生的編碼不適用於 HTTP 請求的 uri,因為其不轉換符號在 HTTP 請求中需要被編碼,例如:&、?- 不轉換符號包括:* A-Z a-z 0-9~!@#$&()=:/,;?+'
decodeURI()
- 和
encodeURI()
相反
axios content type
- 針對 x-www-form-urlencoded 形式的 request 可以用
URLSearchParams()
提供的 API 做處理 - https://gist.github.com/akexorcist/ea93ee47d39cf94e77802bc39c46589b
How to do things
- Write jest test
- Read and run every example in the documents
- Follow the convention from the environment e.g. instead of using redux starter kit, check what your company is using
- If you want to master a thing, you have to sacrifice other things e.g. time for using facebook, etc
- How to estimate target salary based on pension
- Goal and direction should match
- Learn things with a longer lifetime, e.g. computer science > programming language > library > framework
- Learning by listening to others is less efficient than learning by yourself
- Program design is subjective, however, most programmer would agree to DRY and SoC
- Context is everything
- Limitation forces creativity
- Focus on one single thing at a time
- KISS
- SMART
- Be aware of vendor-lock in
- Find and fill knowledge gap
- Every line of of code has to have a reason, a reason has to convince others