redux的原理:
- 创建store,全局通过Provider注入
- reducer实现初始化数据,多个reducer使用combineReducers, 将合并为一个数据对象
- reducer(prevState, action) 根据action的值,间接更新state;
- action定义为一个函数可以接受参数,并对参数进行处理
const add = val => ({ type: 'ADD_TODO', payload: { id: 33, content: 'xxx' })
注意: 当实用全局注入store后,则可以在任意地方获取store参数。
具体实践如下:
一、store
1. 创建store
import { createStore } from "redux";
import reducer from "./reducers/index";
export default createStore(reducer);
2. 数据初始化
import { combineReducers } from "redux";
// 使用两个reducer
import visibilityFilter from "./visibilityFilter";
import todos from "./todos";
export default combineReducers({ todos, visibilityFilter });
// (1) todos
import { ADD_TODO, TOGGLE_TODO } from "../actions/actionTypes" // 自定义action类型
const initialState = {
allIds: [],
byIds: {}
};
// eslint-disable-next-line
export default function(state = initialState, action) {
switch (action.type) {
case ADD_TODO: {
const { id, content } = action.payload;
return { // 只可以对state间接操作,返回一个新的对象
...state,
allIds: [...state.allIds, id],
byIds: {
...state.byIds,
[id]: {
content,
completed: false
}
}
};
}
case TOGGLE_TODO: {
const { id } = action.payload;
return {
...state,
byIds: {
...state.byIds,
[id]: {
...state.byIds[id],
completed: !state.byIds[id].completed
}
}
};
}
default:
return state;
}
}
// (2) visibilityFilter
import { SET_FILTER } from "../actions/actionTypes"
import { VISIBILITY_FILTERS } from "../../static/VisibilityFilters";
const initialState = VISIBILITY_FILTERS.ALL;
const visibilityFilter = (state = initialState, action) => {
switch (action.type) {
case SET_FILTER: {
return action.payload.filter;
}
default: {
return state;
}
}
};
export default visibilityFilter;
store中的数据为: {allId: [], byId: {}, visibilityFilter:'all'}
二、 actions
import {ADD_TODO, TOGGLE_TODO, SET_FILTER} from './actionTypes'
let count = 0; // 全局的计数变量
export const addToDo = content => ({
type: ADD_TODO,
payload: {
id: ++count,
content
}
})
export const toggleTodo = id => ({
type: TOGGLE_TODO,
payload: {id}
})
export const setFilter = filter => ({
type: SET_FILTER,
payload: { filter }
});
三、在组件中具体使用connect
connect(mapStateToProps, mapDispatchToProps)(Component)
例1
import React from 'react'
import { useState } from 'react';
import { connect } from "react-redux";
import { addToDo } from "../store/actions/actions"
function AddTodo({ addToDo }) {
const [input, setInput] = useState('')
const updateInput = input => {
setInput(input)
};
const handleAddTodo = () => {
addToDo(input);
setInput('');
};
return (
<div>
<input
onChange={e => updateInput(e.target.value)}
value={input}
/>
<button className="add-todo" onClick={handleAddTodo}>
Add Todo
</button>
</div>
);
}
export default connect(null, { addToDo })(AddTodo)
// addToDo为action, AddTodo为组件
例2
import React from "react";
import { connect } from "react-redux";
import { setFilter } from "../store/actions/actions";
import { VISIBILITY_FILTERS } from "../static/VisibilityFilters"
const Filter = ({ activeFilter, setFilter }) => {
return (
<div className="visibility-filters">
{Object.keys(VISIBILITY_FILTERS).map((filterKey) => {
const currentFilter = VISIBILITY_FILTERS[filterKey];
return (
<span
key={`visibility-filter-${currentFilter}`}
className={cx(
"filter",
currentFilter === activeFilter && "filter--active"
)}
onClick={() => {
setFilter(currentFilter);
}}
>
{currentFilter}
</span>
);
})}
</div>
);
};
const mapStateToProps = (state) => {
return { activeFilter: state.visibilityFilter };
};
// const mapDispatchToProps = (dispatch) => {
// return {
// handle() {
// dispatch(setFilter)
// }
// }
// }
export default connect(mapStateToProps, { setFilter })(Filter);
例3: 补充一个获取todos的方法
import React from "react";
import { connect } from "react-redux";
import Todo from "./Todo";
import { getTodosByVisibilityFilter } from "../store/selectors"
const TodoList = ({ todos }) => (
<ul className="todo-list">
{todos && todos.length
? todos.map((todo) => {
return <Todo key={`todo-${todo.id}`} todo={todo} />;
})
: "No todos, yay!"}
</ul>
);
const mapStateToProps = (state) => {
const { visibilityFilter } = state; // 初始值为all
const todos = getTodosByVisibilityFilter(state, visibilityFilter);
return { todos };
}
export default connect(mapStateToProps)(TodoList);
// selector.js中通过store获取合成后的list数组
import { VISIBILITY_FILTERS } from "../static/VisibilityFilters";
const getTodosState = store => store.todos; // allIds, byIds, visibilityFilter
const getTodoList = store =>
getTodosState(store) ? getTodosState(store).allIds : []; // allIds
const getTodoById = (store, id) =>
getTodosState(store) ? { ...getTodosState(store).byIds[id], id } : {}; // {content, completed, id}
const getTodos = store => // 映射list [{content, completed, id},....]
getTodoList(store).map(id => getTodoById(store, id));
export const getTodosByVisibilityFilter = (store, visibilityFilter) => {
// 分类筛选, 此时store已经可以完全获取了
const allTodos = getTodos(store);
switch (visibilityFilter) {
case VISIBILITY_FILTERS.COMPLETED:
return allTodos.filter(todo => todo.completed);
case VISIBILITY_FILTERS.INCOMPLETE:
return allTodos.filter(todo => !todo.completed);
case VISIBILITY_FILTERS.ALL:
default:
return allTodos;
}
};
**最后代码 (很简洁!!) **
import React from 'react'
import AddTodo from './AddTodo'
import Todolist from './TodoList';
import Filter from './Filter';
export default function TodoApp() {
return (
<>
<h1>this is Todo List test!!!!</h1>
<AddTodo/>
<Todolist/>
<Filter/>
</>
)
}
基本的思想和代码都如上所示,总结如下:
- 多组件使用的变量放在store中,也可以分模块定义,最后组合为一个对象;
- 操作state时,传参进入action,定义对象
{type: '', payload: ....}
, 保存数据; - 组件连接store啦,
connect(state, {action})(component)
, 使用props即可接收; - reducer根据state和action,更新state操作,不能直接修改,返回一个新的对象(利用扩展运算符); (搞定了)
后文: 接下来打算做个后台管理系统,巩固下知识!!!加油