Action 是把數據從應用(服務器響應,用戶輸入或其它非 view 的數據 )傳到 store 的有效載荷。它是 store 數據的惟一來源。通常來講你會經過 store.dispatch() 將 action 傳到 store。分下邊兩類.html
/* * action 常量 */ export const ADD_TODO = 'ADD_TODO'; export const VisibilityFilters = { SHOW_ALL: 'SHOW_ALL', SHOW_COMPLETED: 'SHOW_COMPLETED', } /* * action 建立函數 */ export function addTodo(text) { return { type: ADD_TODO, text } } export const addTodo = (id)=>{ return { type: EDITORUSERID, id:id } } 複製代碼
是一個純函數,接收舊的 state 和 action,返回新的 state。 (previousState, action) => newState
react
注意:永遠不要在 reducer 裏作這些操做:git
function todos(state = [], action) { switch (action.type) { case ADD_TODO: return [ ...state, { text: action.text, completed: false } ] default: return state } } 複製代碼
combineReducers管理多個Reducergithub
const todoApp = combineReducers({ visibilityFilter, todos }) export default todoApp 當你觸發 action 後,combineReducers 返回的 todoApp 會負責調用兩個 reducer: let nextTodos = todos(state.todos, action) 注意:也能夠 reducer 放到一個獨立的文件中,經過 export 暴露出每一個 reducer 函數import * as reducers from './reducers' 複製代碼
Store 有如下職責:json
import todoApp from './reducers' let store = createStore(todoApp) 複製代碼
createStore() 的第二個參數是可選的, 用於設置 state 初始狀態。這對開發同構應用時很是有用,服務器端 redux 應用的 state 結構能夠與客戶端保持一致, 那麼客戶端能夠將從網絡接收到的服務端 state 直接用於本地數據初始化。redux
let store = createStore(todoApp, window.STATE_FROM_SERVER)
api
Redux 的 React 綁定庫是基於 容器組件和zhan shi組件相分離 的開發思想緩存
展現組件 | 容器組件 | |
---|---|---|
做用 | 描述如何展示(骨架、樣式) | 描述如何運行(數據獲取、狀態更新) |
直接使用 Redux | 否 | 是 |
數據來源 | props | 監聽 Redux state |
數據修改 | 從 props 調用回調函數 | 向 Redux 派發 actions |
調用方式 | 手動 | 一般由 React Redux 生成 |
展現組件就是通常的js文件容器組件每每使用connect(mapStateToProps,mapDispatchToProps)
建立。 mapStateToProps是把容器組件state向展現組件props映射。mapDispatchToProps() 是映射回調方法。例如,咱們但願 VisibleTodoList 向 TodoList 組件中注入一個叫 mOnClick 的 props ,還但願 onTodoClick 能分發 increaseAction 這個 action:bash
const App=connect(
(state)=>({
value:state.count
}),(dispatch)=>({
mOnClick:()=>dispatch(increaseAction)
})
)(Counter);
複製代碼
全部容器組件均可以訪問 Redux store,建議的方式是使用指定的 React Redux 組件 來包裹,讓全部容器組件均可以訪問 store,服務器
let store = createStore(todoApp) render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ) 複製代碼
//建立組件的簡單寫法 const App = () => ( <div> <AddTodo /> <VisibleTodoList /> <Footer /> </div> ) export default App 複製代碼
標準的作法是使用 Redux Thunk
中間件。 action 建立函數除了返回 action 對象外還能夠返回函數。這時,這個 action 建立函數就成爲了 thunk。這個函數會被 Redux Thunk middleware 執行。
咱們仍能夠在 actions.js 裏定義這些特殊的 thunk action 建立函數。
建立thunk action
//thunk action // 雖然內部操做不一樣,你能夠像其它 action 建立函數 同樣使用它: // store.dispatch(fetchPosts('reactjs')) export function fetchPosts(subreddit) { return function (dispatch) { // 首次 dispatch:更新應用的 state 來通知 // API 請求發起了。 dispatch(requestPosts(subreddit)) return fetch(`http://www.subreddit.com/r/${subreddit}.json`) .then( response => response.json(), error => console.log('An error occurred.', error) ) .then(json => dispatch(receivePosts(subreddit, json)) ) } } export function fetchPostsIfNeeded(subreddit) { // 當緩存的值是可用時, // 減小網絡請求頗有用。 return (dispatch, getState) => { if (shouldFetchPosts(getState(), subreddit)) { // 在 thunk 裏 dispatch 另外一個 thunk! return dispatch(fetchPosts(subreddit)) } else { // 告訴調用代碼不須要再等待。 return Promise.resolve() } } } 複製代碼
你能夠利用 Redux middleware 來進行日誌記錄、建立崩潰報告、調用異步接口或者路由等等。應用中間件要改造下createStore()
* 記錄全部被髮起的 action 以及產生的新的 state。
*/
const logger = store => next => action => {
console.group(action.type)
let result = next(action)
console.log('next state', store.getState())
return result
}
let store = createStore(
todoApp,
applyMiddleware(
logger
)
複製代碼
1 action優化 1.1 你能夠寫一個用於生成 action creator 的函數:
function makeActionCreator(type, ...argNames) { return function(...args) { let action = { type } argNames.forEach((arg, index) => { action[argNames[index]] = args[index] }) return action } } const ADD_TODO = 'ADD_TODO' const EDIT_TODO = 'EDIT_TODO' export const addTodo = makeActionCreator(ADD_TODO, 'todo') export const editTodo = makeActionCreator(EDIT_TODO, 'id', 'todo') 複製代碼
1.2異步 Action Creators
export function loadPosts(userId) { return { // 要在以前和以後發送的 action types types: ['LOAD_POSTS_REQUEST', 'LOAD_POSTS_SUCCESS', 'LOAD_POSTS_FAILURE'], // 檢查緩存 (可選): shouldCallAPI: (state) => !state.users[userId], // 進行取: callAPI: () => fetch(`http://myapi.com/users/${userId}/posts`), // 在 actions 的開始和結束注入的參數 payload: { userId } }; } 複製代碼
2.reducer重構
方法抽取
function addTodo(state, action) { ... return updateObject(state, {todos : newTodos}); } function todoReducer(state = initialState, action) { switch(action.type) { case 'SET_VISIBILITY_FILTER' : return setVisibilityFilter(state, action); case 'ADD_TODO' : return addTodo(state, action); default : return state; } } 複製代碼
善用combineReducers
函數
// 使用 ES6 的對象字面量簡寫方式定義對象結構
const rootReducer = combineReducers({
todoReducer,
firstNamedReducer
});
const store = createStore(rootReducer);
複製代碼
3.大多數應用會處理多種數據類型,一般能夠分爲如下三類:
一個典型的應用 state 大體會長這樣:
{
domainData1 : {},
domainData2 : {},
appState1 : {},
appState2 : {},
ui : {
uiState1 : {},
uiState2 : {},
}
}
複製代碼
必要時可採用 Redux-ORM