ReactNative Redux - fantasy0107/notes GitHub Wiki
技巧
- 取值的時候拿單一值, 盡量不要拿object, array
- 用 array 會有問題 - redux 不知道在 array 裡面的值是否有改過 所以會一直render 重跑
state container
概念
Provider - 讓 redux store 在 app 裡可以被存取
connect() - 讓 component 和 redux 綁定
component 綁定 redux store/action
main pieces
connect() - 封裝對於 store 的 process
-
取得 data from redux store
-
dispatch action to store 從任何的 connected component
-
有兩個基本的 arguments
- mapStateToProps - 當 store state 改變時呼叫它
- mapDispatchToProps - 可以是 function 或 object
- object - action creators, 每個 action creator 將會變成 prop function 會自動 dispatch action
const mapStateToProps = (state, ownProps) => ({
// ... computed data from state and optionally ownProps
});
const mapDispatchToProps = {
// ... normally is an object full of action creators
};
// `connect` returns a new function that accepts the component to wrap:
const connectToStore = connect(
mapStateToProps,
mapDispatchToProps
);
// and that function returns the connected, wrapper component:
const ConnectedComponent = connectToStore(Component);
// We normally do both in one step, like this:
connect(
mapStateToProps,
mapDispatchToProps
)(Component);
Allows state to be updated via dispatch(action);
actions
payloads
送出資料從你的應用程式到你儲存的地方(store) 它是唯一的資料來源對於儲存的地方(store)
reducers
update the state according to those actions
store
- 只會有一個 store 在 redux app
- 儲存 state
- 允許取得 state - getState()
- 允許更新 state - dispatch(action);
mapStateToProps - 從 Redux 拿東西
const mapStateToProps = state => ({
user : state.user,
....
})
export default connect(
mapStateToProps,
{
action method
}(componentName)
);
axios create
- headers - 設定 headers
const axiosInstance = axios.create({
headers: { 'Content-Type': 'application/json' }
});
- baseURL - API 來源網址
const axiosInstance = axios.create({
baseURL: 'api.tw/api/v1',
});
- transformResponse - 改變 api 回傳回來的格式或做一些處理
axios.defaults.transformResponse.concat((data, headers) => {
// data 和 header 相關處理
return data;
}
其它
-
axios request Config - axios create 可以設定的相關參數
-
[axios response schema] - api 回傳資料回來後的格式 (https://github.com/axios/axios#response-schema)
-
Config Defaults - 設定 default 的 request config (傳每個 request 預設都會用這個設定 在請求每個 api 的時候)
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
- action 裡面
export const login = () => async (dispatch, getState, api) => {
// api 就是一個 axios instance
// getState() 是 redux Store
api.defaults.headers.common['Authorization'] = Authorization;
};
- redux thunk - withExtraArgument
附加而外的參數
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument(api))
)
// 稍後 api 就會被額外的帶過去 (單一)
function fetchUser(id) {
return (dispatch, getState, api) => {
// you can use api here
}
}
// 多個參數
const store = createStore(
reducer,
applyMiddleware(thunk.withExtraArgument({ api, whatever }))
)
// later
function fetchUser(id) {
return (dispatch, getState, { api, whatever }) => {
// you can use api and something else here
}
}
- 使用 redux thunk - applyMiddleware()
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
- redux persistCombineReducers 指定 reducer
const reducer = persistCombineReducers({
key: 'aaa',
storage: AsyncStorage,
}, reducers);
// 和 redux 綁定
const store = createStore(reducer, applyMiddleware(...middlewares));
- 新舊值造成的渲染問題 //當 redux 在 reducer 中處理的時候回傳的結果會跟 redux store 中的相對應的 state 比較看有無不同, 有不同才會重新渲染畫面
//array
var newArray = oldArray.slice(); //複製array 並且是一個新的 array reference
// object 複製 當只有一層的時候
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
// object 複製 (不論有幾層前提是要可以被轉成 json 像 function(){} 就不可以, 但是在 redux 中不會有 fun 所以建議用這種)
var obj1 = { body: { a: 10 } };
var obj2 = JSON.parse(JSON.stringify(obj1));
問題
可以用 directory 的方式管理 reducers
import reducers from './reducers'; import 資料夾預設會去讀取資料夾裡的 index.js
//reducers/index.js
import user from './user';
export default {
user
}
reducer 裡的寫法
import { combineReducers } from 'redux';
import {
ADD
} from '../actions/const';
const A = (state = {}, { type, payload }) => {
switch(type)
{
case ADD:
return state;
default:
return state;
}
}
export default combineReducers({
A, //欄位一
B, //欄位二
C //欄位三
});
redux 用 array 會有問題
redux 不知道在 array 裡面的值是否有改過 所以會一直render 重跑
mapStateToProps 用 shallow comparisons 的方式來比較
Shallow compare works by checking if two values are equal in case of primitive types like string, numbers and in case of object it just checks the reference. So if you shallow compare a deep nested object it will just check the reference not the values inside that object.
因為 object 和 array 在 mapStateToProps 會一直觸發渲染
// 去比較 mapStateToProps 是否一樣
areStatePropsEqual: (next: Object, prev: Object) => {
return JSON.stringify(next) === JSON.stringify(prev);
}