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