@zhongjianxin
2018-07-20T09:55:13.000000Z
字数 7883
阅读 1103
OOCL
Tutorials:
Redux:https://www.valentinog.com/blog/react-redux-tutorial-beginners/
Redux handle API call: https://medium.com/@stowball/a-dummys-guide-to-redux-and-thunk-in-react-d8904a7005d3
Case study:https://blog.csdn.net/fengyinchao/article/details/51566555?from=singlemessage&isappinstalled=0
Basic Redux Starter 2018:https://www.valentinog.com/blog/react-redux-tutorial-beginners/#React_Redux_tutorial_Redux_store_methods
(1)Web 应用是一个状态机,视图与状态是一一对应的。
(2)所有的状态,保存在一个对象里面。
第一天
第五天
第二十天
解脱
按照开发的内容,可以把前端团队分为两个小组: “布局组” 和 “逻辑组”,每个小组有2种任务,一共4种任务:
布局组 - 负责 contianer、component 部分
任务1:静态布局 - 使用 HTML + CSS 静态布局
任务2:动态布局 - 使用 JSX 语法对静态布局做动态渲染处理, 设计State的结构
逻辑组 - 负责 action、reducer 部分
任务1:action 开发 - 制作 redux 流程的 action: action调用时,考虑是远程的API call+ store 更新,还是仅仅只是store更新
任务2:reducer 开发 - 制作 redux 流程的 reducer:相应需要更新store的action,注意数据的不可修改性. 这里需要考虑state是深拷贝还是浅拷贝:深拷贝性能低,浅拷贝高效 且能达到同样的效果
布局组 要求对 HTML + CSS 布局比较熟悉,只需要会简单的 js 即可, 不需要完整地理解redux流程。
逻辑组 要求对 js 比较熟悉,最好可以比较完整地理解redux流程, 但基本不需要涉及HTML + CSS布局工作。
class: middle center
class: middle center
layout: true
props => <Component {...props} />
...
data => <Application {...data} />
const TodoMVC = props => (
<Container>
<Header>
<Filters />
</Header>
<TodoList>
<TodoItem>
<Status />
<Text />
<TextEditor />
</TodoItem>
{...}
</TodoList>
<Footer />
</Container>
)
???
- Dynamic use input
class: middle
layout: false
layout: true
data => <Application {...data} />
||
﹀
(data <=> <Application />) <=> User
||
﹀
State -----> View(Component)
︿ /
\ /
\ ﹀
User
layout: false
.center[
import { createStore } from 'redux'
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
const store = createStore(counterReducer)
store.subscribe(() => {
console.log(store.getState())
})
store.dispatch({ type: 'INCREMENT' })
setState
API to update Component
import { Provider as Redux, connect } from 'react-redux'
const initialState = { count: 0 }
const store = createStore(counterReducer, initialState)
const App = props => <div>Redux Counter: {props.count}</div>
const ConnectedApp = connect(state => state)(App)
ReactDom.render(
<Redux store={store}>
<ConnectedApp />
</Redux>
, rootDom)
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
const incrementAction = { type: 'INCREMENT' }
const store = createStore(counterReducer)
store.dispatch(incrementAction)
class: middle center
react-redux
layout: true
let x = 1 + 2;
let foo = () => 1 + 2;
const incrementAction = { type: 'INCREMENT' }
const incrementActionThunk = () => ({ type: 'INCREMENT' })
const incrementActionAsyncThunk = (dispatch) => {
setTimeout(() => {
dispatch(incrementAction)
}, 1000)
}
const incrementIfOddActionAsyncThunk = (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 !== 0) {
dispatch(incrementAction)
}
}
layout: false
.center[
]
layout: true
({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
({ dispatch, getState }) => {
return next => {
return action => {
if (typeof action === 'function') {
return action(dispatch, getState);
}
return next(action);
};
}
}
console.log
every action with action type
import { createStore, applyMiddleware, compose } from 'redux'
import { createDevTools } from 'redux-devtools'
import LogMonitor from 'redux-devtools-log-monitor'
import DockMonitor from 'redux-devtools-dock-monitor'
const DevTool = createDevTools(
<DockMonitor toggleVisibilityKey='ctrl-h'
changePositionKey='ctrl-q'
changeMonitorKey='ctrl-m'>
<LogMonitor />
</DockMonitor>
)
const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(thunk), DevTools.instrument())
)
render(
<Provider store={store}>
<div><TodoApp /><DevTools /></div>
</Provider>
document.getElementById('app')
)
layout: false
const increment = () => { type: INCREMENT }
const incrementTwiceWith = (x) => {
type: INCREMENT_TWICE_WITH,
payload: x * 2
}
const reducer = (state, action) => ({
switch (action.type) {
case INCREMENT:
return state + 1
case INCREMENT_TWICE_WITH:
return state + action.payload
default:
return state
}
})
import { createAction, handleActions } from 'redux-actions'
const increment = createAction(INCREMENT)
const incrementTwiceWith = createAction(INCREMENT_TWICE_WITH, x => x * 2)
const reducer = handleActions({
[INCREMENT]: state => state + 1,
[INCREMENT_TWICE_WITH]: (state, action) => state + action.payload * 2
})
Refactor your practice with the logger
and redux-action
import { createAction, handleActions } from 'redux-actions'
const increment = createAction(INCREMENT)
const incrementTwiceWith = createAction(INCREMENT_TWICE_WITH, x => x * 2)
const reducer = handleActions({
[INCREMENT]: state => state + 1,
[INCREMENT_TWICE_WITH]: (state, action) => state + action.payload * 2
})
import { createStore, applyMiddleware, compose } from 'redux'
import { createDevTools } from 'redux-devtools'
import LogMonitor from 'redux-devtools-log-monitor'
import DockMonitor from 'redux-devtools-dock-monitor'
const DevTool = createDevTools(
<DockMonitor toggleVisibilityKey='ctrl-h'
changePositionKey='ctrl-q'
changeMonitorKey='ctrl-m'>
<LogMonitor />
</DockMonitor>
)
const store = createStore(
rootReducer,
initialState,
compose(applyMiddleware(thunk), DevTools.instrument())
)
layout: true
const incrementActionThunk = () => ({ type: 'INCREMENT' })
const reducer = (state, action) => ({
if (action.type === 'INCREMENT') {
state = state + 1
}
})
const updateCount = (dispatch, getState) => ({
type: 'INCREMENT',
payload: getState().count + 1
})
const reducer = (state, action) => ({
if (action.type === 'INCREMENT') {
state = action.payload
}
})
???
Complex action or Complex reducer
- Event system disadvantage
const increment = () => { type: INCREMENT }
const incrementTwiceWith = (x) => {
type: INCREMENT_TWICE_WITH,
payload: x * 2
}
const incrementWith = x => {
type: INCREMENT_WITH,
payload: x
}
const increment = () => dispatch => dispatch(incrementWith(1))
const incrementTwiceWith = (x) => dispatch => dispatch(incrementWith(x * 2))
const initialState = {
user: {
id: null
},
isLoading: false
}
const login = (username, password) => (dispatch, getState) => {
const { isLoading } = getState()
if (!isLoading) {
dispatch(loading(true))
}
API.login({ username, password }).then(user => {
dispatch(loading(false))
dispatch(user ? loginSuccess(user) : loginFail())
}).catch(e => {
dispatch(loading(false))
loginFail(e)
})
}
layout: false
redux-actions
react-redux
to connect your action with componentlayout: true
class: center middle
const INCREMENT_ASYNC = 'INCREMENT_ASYNC'
const incrementAsync = createAction(INCREMENT_ASYNC)
const incrementAsyncSaga = function* incrementAsync() {
return new Promise((res, rej) => {
// Or do something else async
setTimeout(() => res(), 1000)
})
}
const rootSaga = function* root() {
yield [
takeLatest(INCREMENT_ASYNC, incrementAsyncSaga)
]
}
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
reducer,
applyMiddleware(thunk, sagaMiddleware),
initialState
)
sagaMiddleware.run(rootSaga)
Refactor previous Practice Complex Action into Saga
layout: false
class: center middle
.left[
class: center middle