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