redux初探
action是一个普通对象 里面必须有一个type字段,代表将要执行的行为,其他字段自己规划。
action只是描述了将要发生的事情并不能直接修改状态
action创建函数 尽量是一个纯函数,他返回的是action对象
middleware 接受一个next() 的dispatch函数,返回了一个dispatch函数,将返回的dispatch函数作为下一个middleware的next() 一次类推可以达到链式的调用
它提供的是位于 action 被发起之后,到达 reducer 之前的扩展点。 你可以利用 Redux middleware 来进行日志记录、创建崩溃报告、调用异步接口或者路由等等。
不管链式调用几次dispatch 最后一次调用dispatch 必须是一个action不能是其他的。来达到数据来源的起点。
import React from "react"; import { render } from "react-dom"; import { Provider } from "react-redux"; import { createStore ,compose,applyMiddleware} from "redux"; import App from "./components/app"; import reducers from './reducers/index' import {addTodo} from './actions/index' const enhancers = compose( window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); const store = createStore(reducers,enhancers); const logger = (store)=>next=>action=>{ console.log('action',action) let result = next(action) console.log('state',store.getState()) return result } console.log(logger(store)(store.dispatch)(addTodo('abc'))) //手动实现一个middleware function middleware(stroe,middlewares){ middlewares = middlewares.slice() middlewares.reverse() let dispatch = store.dispatch middlewares.forEach(middleware => { dispatch = middleware(stroe)(dispatch) }) return Object.assign({},store,{dispatch}) } console.log(middleware(store,[logger])) render( <Provider store={store}> <App /> </Provider>, document.getElementById("root") );
let nextTodoId = 0; export const addTodo = (text) => { return { type: "ADD", id: nextTodoId++, text, }; }; export const setVisibilityFilter = (filter) => ({ type: "SET_VISIBILITY_FILTER", filter, }); export const toggleTodo = (id) => ({ type: "TOGGLE_TODO", id, }); export const VisibilityFilters = { SHOW_ALL: "SHOW_ALL", SHOW_COMPLETED: "SHOW_COMPLETED", SHOW_ACTIVE: "SHOW_ACTIVE", };
reducer函数接收二个参数,一个是旧的状态树,一个是actions对象 返回的是一个新的状态树
可以创建多个子reducer,分别负责状态树中的一部分。最后创建一个根reducers
//子reducers const todos = (state = [], action) => { switch (action.type) { case "ADD": return [ ...state, { id: action.id, text: action.text, completed: false, }, ]; break; case "TOGGLE_TODO": return state.map((todo) => todo.id == action.id ? { ...todo, completed: !todo.completed } : todo ); break; default: return state; break; } }; export default todos
//根reducers import React from 'react' import { combineReducers } from 'redux' import todos from './todos' import visibilityFilter from './visibilityFilter'
//自定义根reducers // const todoApp = (state={},action)=>({ // todos:todos(state.todos,action), // visibilityFilter:visibilityFilter(state.abc,action) // }) export default combineReducers({todos,visibilityFilter}) //combineReducers 将reducers 拆分成多个子reducers 并执行
最后通过createStore 将状态树传递到页面组件树当中
import React from "react"; import { render } from "react-dom"; import { Provider } from "react-redux"; import { createStore ,compose} from "redux"; import App from "./components/app"; import reducers from './reducers/index' const enhancers = compose( window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() ); const store = createStore(reducers,enhancers); render( <Provider store={store}> <App /> </Provider>, document.getElementById("root") )
将redux应用到组件中时分为容器组件和展示组件,容器组件需要将展示组件连接到store上
//容器组件 import React from 'react' import { connect } from 'react-redux' import TodoList from '../components/TodoList' import {toggleTodo,VisibilityFilters} from '../actions/index' const getVisibleTodos = (todos,filter)=>{ switch (filter) { case 'SHOW_ALL': return todos break; case 'SHOW_COMPLETED': return todos.filter((todo)=>todo.completed) break; case 'SHOW_ACTIVE': return todos.filter(t=>!t.completed) break; default: throw new Error('Unknown filter: ' + filter) } } const mapStateToProps = (state, ownProps) => { console.log(state) return { todos: getVisibleTodos(state.todos,state.visibilityFilter) } } const mapDispatchToProps = (dispatch, ownProps) => { return { toggleTodo: (id) => { dispatch(toggleTodo(id)) } } } export default connect(mapStateToProps,mapDispatchToProps)(TodoList)
//展示组件 import React from 'react' import Todo from './Todo' const TodoList = ({todos,toggleTodo})=>{ return ( <ul> {todos.map(todo=> <Todo change={()=>toggleTodo(todo.id)} key={todo.id} {...todo} /> )} </ul> ) } export default TodoList