@zhongjianxin
2018-07-20T01:55:13.000000Z
字数 7883
阅读 1735
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 + 1case 'DECREMENT':return state - 1default: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 + 1case 'DECREMENT':return state - 1default:return state}}const incrementAction = { type: 'INCREMENT' }const store = createStore(counterReducer)store.dispatch(incrementAction)
class: middle center
react-reduxlayout: 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 + 1case INCREMENT_TWICE_WITH:return state + action.payloaddefault: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-actionsreact-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 asyncsetTimeout(() => 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