Store with complex state

添加radio实现过滤功能

  1. import React from 'react'
  2. import Notes from './components/Notes'
  3. import NewNote from './components/NewNote'
  4. const App = () => {
  5. const filterSelected = (value) => {
  6. console.log(value)
  7. }
  8. return (
  9. <div>
  10. <NewNote />
  11. <div>
  12. all{' '}
  13. <input
  14. type="radio"
  15. name="filter"
  16. onChange={() => filterSelected('ALL')}
  17. />
  18. important{' '}
  19. <input
  20. type="radio"
  21. name="filter"
  22. onChange={() => filterSelected('IMPORTANT')}
  23. />
  24. nonimportant{' '}
  25. <input
  26. type="radio"
  27. name="filter"
  28. onChange={() => filterSelected('NONIMPORTANT')}
  29. />
  30. </div>
  31. <Notes />
  32. </div>
  33. )
  34. }
  35. export default App

input组件type为radio, 都有相同的name, 形成一个单选按钮组
image.png

Combined reducers

单选按钮组的状态也应该存储在store中
即使用store.getState()应得到下面的值

  1. {
  2. notes: [
  3. { content: 'reducer defines how redux store works', important: true, id: 1},
  4. { content: 'state of store can contain any data', important: false, id: 2}
  5. ],
  6. filter: 'IMPORTANT'
  7. }

为filter创建单独的reducer

  1. const filterReducer = (state = 'ALL', action) => {
  2. switch (action.type) {
  3. case 'SET_FILTER':
  4. return action.filter
  5. default:
  6. return state
  7. }
  8. }
  9. export const filterChange = (filter) => {
  10. return {
  11. type: 'SET_FILTER',
  12. filter,
  13. }
  14. }
  15. export default filterReducer

将filterReducer和noteReducer组合成新的reducer

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import { createStore, combineReducers } from 'redux'
  4. import noteReducer from './reducers/noteReducer'
  5. import filterReducer from './reducers/filterReducer'
  6. import { filterChange } from './reducers/filterReducer'
  7. import { createNote } from './reducers/noteReducer'
  8. const reducer = combineReducers({
  9. notes: noteReducer,
  10. filter: filterReducer,
  11. })
  12. const store = createStore(reducer)
  13. console.log(store.getState())
  14. const renderApp = () => {
  15. ReactDOM.render(
  16. // <Provider store={store}>
  17. // <App />
  18. // </Provider>,
  19. <div />,
  20. document.getElementById('root')
  21. )
  22. }
  23. renderApp()
  24. // store.subscribe(renderApp)
  25. store.subscribe(() => console.log(store.getState()))
  26. store.dispatch(filterChange('IMPORTANT'))
  27. store.dispatch(
  28. createNote('combineReducers forms one reducer from many simple reducers')
  29. )

通过combineReducers将多个reducer组合成一个复合reducer
组合reducer的工作方式使得每个action 在组合reducer的每个部分都得到处理。 通常只有一个reducer对任何给定的action感兴趣,但是在有些情况下,多个reducer根据相同的action改变它们各自的状态部分。

Finishing the filters

将filter分离到单独的组件

  1. import React from 'react'
  2. import { filterChange } from '../reducers/filterReducer'
  3. import { useDispatch } from 'react-redux'
  4. const VisibilityFilter = () => {
  5. const dispatch = useDispatch()
  6. return (
  7. <div>
  8. all{' '}
  9. <input
  10. type="radio"
  11. name="filter"
  12. onChange={() => dispatch(filterChange('ALL'))}
  13. />
  14. important{' '}
  15. <input
  16. type="radio"
  17. name="filter"
  18. onChange={() => dispatch(filterChange('IMPORTANT'))}
  19. />
  20. nonimportant{' '}
  21. <input
  22. type="radio"
  23. name="filter"
  24. onChange={() => dispatch(filterChange('NONIMPORTANT'))}
  25. />
  26. </div>
  27. )
  28. }
  29. export default VisibilityFilter

通过修改Notes组件的useSelector实现过滤功能

  1. const Notes = () => {
  2. const dispatch = useDispatch()
  3. const notes = useSelector((state) => {
  4. if (state.filter === 'ALL') {
  5. return state.notes
  6. }
  7. return state.filter === 'IMPORTANT'
  8. ? state.notes.filter((note) => note.important)
  9. : state.notes.filter((note) => !note.important)
  10. })
  11. // ...
  12. }

Redux DevTools

可以安装Redux DevToolsChrome插件, 用于监视redux-store的状态和改变它的action
在调试时,还有软件库redux-devtools-extension
安装

  1. npm install --save-dev redux-devtools-extension

createStore时使用composeWithDevTools()

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. import { createStore, combineReducers } from 'redux'
  4. import { Provider } from 'react-redux'
  5. import noteReducer from './reducers/noteReducer'
  6. import filterReducer from './reducers/filterReducer'
  7. import App from './App'
  8. import { composeWithDevTools } from 'redux-devtools-extension'
  9. const reducer = combineReducers({
  10. notes: noteReducer,
  11. filter: filterReducer,
  12. })
  13. const store = createStore(reducer, composeWithDevTools())
  14. const renderApp = () => {
  15. ReactDOM.render(
  16. <Provider store={store}>
  17. <App />
  18. </Provider>,
  19. document.getElementById('root')
  20. )
  21. }
  22. renderApp()

重新启动应用,此时在控制台会看到Redux标签,可以清楚地看到store和action的变化
image.png