React - Redux - 教學
我為了教別人Redux,反而自己因此受惠學會一點點Redux的概念
原本,對方給我原文版的
https://redux.js.org/basics/example/
後來我找到中文版的解說
https://chentsulin.github.io/redux/index.html
可以參看線上的的程式碼
https://codesandbox.io/s/github/reduxjs/redux/tree/master/examples/todos
可以從src底下的index.js做為進入點開始看
可能要學Redux要有一個叫State的概念。
會先建立一個Redux如
import { createStore } from 'redux'
const store = createStore(rootReducer)
這個store ,就會有自己的state
而如果要改變這個store的state,必須使用store的方法
store.dispatch
但因為範例已經將store設定到 Provider
<Provider store={store}>
所以該tag底下的所有元件,都可直接dispatch,而不必加上「store.」
dispatch會放入更動的動作(action)與資料
如使用
store.dispatch({ type: 'INCREMENT' })
或在component裡面則是如下
dispatch(addTodo(input.value))
以上這個動作會變成如下
dispatch({type: 'ADD_TODO',id: nextTodoId++,text})
這個會觸發所有store底下的所有state屬性
store所有的state屬性,其實就在一開始包版時就放入的資料
const store = createStore(rootReducer)
rootReducer則會去看reducers/index.js
裡面會有如下
export default combineReducers({todos,visibilityFilter})
這其實也有點像
export default combineReducers(state)的感覺(我蝦猜的)
所以當dispatch後,就會觸發todos及visibilityFilter兩個的state
todos的會如下
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo =>
(todo.id === action.id)
? {...todo, completed: !todo.completed}
: todo
)
default:
return state
}
}
export default todos
而visibilityFilter 會如下
import { VisibilityFilters } from '../actions'
const visibilityFilter = (state = VisibilityFilters.SHOW_ALL, action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
export default visibilityFilter
為action就是dispatch裡面放的東西 dispatch(action)
所以會用action.type來判斷,是不是跟自己有關,跟自己有關,就會改更自己的state(todos或visibilityFiltre)
在state變更後,有關的component或containers也會隨著應變
在Components下的程式
會有如
const Link = ({ active, children, onClick }) => (
<button
onClick={onClick}
disabled={active}
style={{
marginLeft: '4px',
}}
>
{children}
</button>
)
其實就是
const Link = (我的屬性成員) => (我的畫面)
另外在用
Link.propTypes = {
active: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
onClick: PropTypes.func.isRequired
}
說明屬性成員,的資料型態,及是否必填
再來是
export default Link
讓外部程式看得見
在containers有VisibleTodoList.js
如下
const mapStateToProps = state => ({
todos: getVisibleTodos(state.todos, state.visibilityFilter)
})
const mapDispatchToProps = dispatch => ({
toggleTodo: id => dispatch(toggleTodo(id))
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
感覺就是,我是跟VisibleTodoList是跟TodoList有關,就是一種類似繼承的概念,
並透過connect,將屬性與他的物件屬性連結在一起。
這像是動態注入還是相依性注入的概念,也就是TodoList不先寫死他的預設值及處理方式,而是由他的繼承類別,去幫他實作這部分。
就像TodoList是介面,而VisibleTodoList是實作後的類別
在Link.js有
const Link = ({ active, children, onClick })
children,應該也一個關鍵字,也就是他的元件之間的資料或dom
如
<FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>
Active
</FilterLink>
Active就是children
而在 FilterLink.js裡有
const mapStateToProps = (state, ownProps) => ({
active: ownProps.filter === state.visibilityFilter
})
const mapDispatchToProps = (dispatch, ownProps) => ({
onClick: () => dispatch(setVisibilityFilter(ownProps.filter))
})
看 有ownProps及 ownProps
大概也是關鍵字,是屬於自己這個tag的專有屬性。
大概到這裡,很多稿不懂得邏輯,應該就搞懂了。