-
Notifications
You must be signed in to change notification settings - Fork 0
Redux 基本核心概念 #28
Comments
核心概念
|
三个原则
即整个应用的 单一 console.log(store.getState())
/* Prints
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
*/
唯一修改 这是为了确保 store.dispatch({
type: 'COMPLETE_TODO',
index: 1
})
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
})
为了展示当前应用的
import { combineReducers, createStore } from 'redux'
function visibilityFilter (state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
function todos (state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
return state.map((todo, index) => {
return index === action.index
? Object.assign({}, todo, {
completed: true
})
: todo
})
default:
return state
}
}
const reducer = combineReducers({ visibilityFilter, todos })
const store = createStore(reducer) |
Actions
const ADD_TODO = 'ADD_TODO' // Actions
{
type: ADD_TODO,
text: 'Build my first Redux app'
}
import { ADD_TODO, REMOVE_TODO } from './actionTypes'
在一个 Action Creators
在 function addTodo(text) {
return {
type: ADD_TODO,
text
}
} 在传统的 Flux 架构中, function addTodoWithDispatch(text) {
const action = {
type: ADD_TODO,
text
}
dispatch(action)
} 而在 dispatch(addTodo(text))
dispatch(completeTodo(index)) 可选地,你可以创建一个实现绑定的自动 const boundAddTodo => dispatch(addTodo(text))
const boundCompleteTodo => dispatch(completeTodo(index)) 现在你可以直接调用他们: boundAddTodo(text)
boundCompleteTodo(index)
示例代码
/**
* action types
*/
export const ADD_TODO = 'ADD_TODO'
export const TOGGLE_TODO = 'TOGGLE_TODO'
export const SET_VISIBILITY_FILTER = 'SET_VISIBILITY_FILTER'
/**
* other constants
*/
export const VisibilityFilters = {
SHOW_ALL: 'SHOW_ALL',
SHOW_COMPLETED: 'SHOW_COMPLETED',
SHOW_ACTIVE: 'SHOW_ACTIVE'
}
/**
* action creators
*/
export function addTodo(text) {
return { type: ADD_TODO, text }
}
export function toggleTodo(index) {
return { type: TOGGLE_TODO, index }
}
export function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter }
} |
Reducers
设计
|
Store在之前章节,我们 定义了
在一个 如果你有一个 import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp) 可选地,你可向 const store = createStore(todoApp, window.STATE_FROM_SERVER) 分发 Actionsimport {
addTodo,
toggleTodo,
setVisibilityFilter,
VisibilityFilters
} from './actions'
// 打印初始 state
console.log(store.getState())
// 每次 state 改变,都会打印新的 state
// 注意 subscribe() 返回的一个函数可用于注销监听器
const unsubscribe = store.subscribe(() => console.log(store.getState()))
// 分发一些 actions
store.dispatch(addTodo('Learn about actions'))
store.dispatch(addTodo('Learn about reducers'))
store.dispatch(addTodo('Learn about store'))
store.dispatch(toggleTodo(0))
store.dispatch(toggleTodo(1))
store.dispatch(setVisibilityFilter(VisibilityFilters.SHOW_COMPLETED))
// 停止监听 state 的更新
unsubscribe() |
Flux standard actionExample一个基础的 Flux Standard Action: {
type: 'ADD_TODO',
payload: {
text: 'Do something.'
}
} 一个展示了一个错误的的 Flux standard action, 类似于一个 rejected 的 Promise 实例。 {
type: 'ADD_TODO',
payload: new Error(),
error: true
} Actions一个
一个
一个
|
异步的 Action Creators我们如何使用定义好的同步
当一个 import fetch from 'cross-fetch'
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
}
export const INVALIDATE_SUBREDDIT = 'INVALIDATE_SUBREDDIT'
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit
}
}
// 来见识我们第一个 thunk action creator!
// 尽管现在的函数内部不同于先前的 action creator,但你仍可以就像先前的 action creator
// 的调用方式来调用异步的 action creator:store.dispatch(fetchPosts('reactjs'))
export function fetchPosts(subreddit) {
// Thunk middleware knows how to handle functions.
// Thunk 中间件知道如何处理这些异步 action creator 函数。
// It passes the dispatch method as an argument to the function,
// 中间件会把 dispatch 方法作为本函数的一个参数传入,
// thus making it able to dispatch actions itself.
// 进而使得它自己能够分发对应的 action。
return function(dispatch) {
// First dispatch: the app state is updated to inform
// 第一个 dispatch; 更新 App 状态以通知 API 调用开始。
// that the API call is starting.
dispatch(requestPosts(subreddit))
// The function called by the thunk middleware can return a value,
// 通过 Thunk 中间件调用的函数可返回一个值,
// that is passed on as the return value of the dispatch method.
// 该值可作为 dispatch 方法的返回值传递。
// In this case, we return a promise to wait for.
// 在这种情况下,我们返回一个处于等待状态的 Promise 实例
// This is not required by thunk middleware, but it is convenient for us.
// 对于 thunk 中间件,返回 Promise 实例并不是必须的,但这可为我们提供很多的便利。
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
// Do not use catch, because that will also catch
// 不要使用 catch 函数
// any errors in the dispatch and resulting render,
// 因为所有的错误会在 dispatch 和 结果渲染中被处理,
// causing a loop of 'Unexpected batch number' errors.
// 使用 catch 将导致一个 `Unexpected batch number` 的错误
// https://github.com/facebook/react/issues/6895
error => console.log('An error occurred.', error)
)
.then(json =>
// We can dispatch many times!
// 我们可以 dispatch 很多次!
// Here, we update the app state with the results of the API call.
// 在这,我们随着 API 调用的返回结果来更新 app 的 state
dispatch(receivePosts(subreddit, json))
)
}
} |
而不是直接修改
state
,你可以指定任意修改object
的mutations
,我们叫这种mutations
叫做actions
。然后你写下一个叫做reducer
的**纯函数**用于决定每一个actions
是如何转换整个app
的state
。在一个典型的
Redux app
中,只有唯一一个store
和root reducing
函数(即root reducer
)。随着你的app
的增长,你可以将root reducer
拆分为分布在state
树不同部分的更小的reducer
。这就像在一个React app
中只存在一个根组件,但它是由许多更小的组件组合而成的。这个架构似乎看起来对于一个
counter
应用是有点杀鸡用牛刀(overkill
)了,但是这种模式的绝妙之处在于它可以很好的拓展至一个庞大并且复杂的app
。它也是非常强劲的开发者工具,因为可追踪每个引起mutation
的源头action
。你可以记录用户绘画并且通过重放每一个action
来重现用户会话。The text was updated successfully, but these errors were encountered: