欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

redux学习总结与应用

程序员文章站 2024-01-09 20:12:28
文章目录redux重要知识点Redux的三大原则StoreActionReducerRedux的三大核心之间的关系react与redux配合使用的流程原理redux重要知识点首先,我先给出我学习react框架的参考教程,以下内容都是我依据此教程的个人总结。redux中文教程redux 是 JavaScript 状态容器,提供可预测化的状态管理。redux与react之间本身并无直接关系,但是它俩可以完美的搭配使用。简单来说,在流行的MVC三层架构理念中,react主要负责View层数据渲染,那么re...

redux重要知识点

首先,我先给出我学习react框架的参考教程,以下内容都是我依据此教程的个人总结。
redux中文教程
redux 是 JavaScript 状态容器,提供可预测化的状态管理。redux与react之间本身并无直接关系,但是它俩可以完美的搭配使用。简单来说,在流行的MVC三层架构理念中,react主要负责View层数据渲染,那么redux就主要负责Model层的数据存储与一些状态管理。
redux安装:

npm install --save redux

很多时候也许还要安装redux相关的库:

npm install --save react-redux
npm install --save-dev redux-devtools

Redux的三大原则

首先介绍redux的三大原则,其每一条原则都对应于下面的每一个核心:

  • 单一数据源: 简单来说就是在整个应用中只允许有一个store
  • State 是只读的: 即state不允许被更改,若想产生新的state也只能通过action触发。
  • 使用纯函数来执行修改 这里的修改是指产生新的state,而纯函数就是指reducer

也许大家还并不清楚store,action以及reducer究竟是什么,没关系,带着三大原则接着往下看。

Store

store就是redux的数据容器,存储着当前项目里的所有数据,所以有且只有一个。在与react框架结合使用时,store通常是与react框架的*父组件绑定在一起。
Talk is cheap,show you the code:

// 创建store
let store = createStore(todoApp)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

还有几个和store相关的api,这里我先不作讲解,后面内容有用到时再进行讲述。

Action

action是把数据从应用(如果是与react框架结合使用,那么这里的应用可以值react的component组件)传到 store 的有效载荷。它是 store 数据的唯一来源,一般来说是通过 store.dispatch() 将 action 传到 store。
action 本质上是 Object,按照约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作。不同的action的type代表不同的状态,所以state的更新只能由action触发。
下面就是四种不同的action实例:

let nextTodoId = 0;
const TODO_ADD = 'TODO_ADD';
export const actionAddTodo = (todo: IToDo) => ({
  type: TODO_ADD,
  id: nextTodoId++,
  todo
});

const TODO_EDIT = 'TODO_EDIT';
export const actionEditTodo = (id: number, todo: IToDo) => ({
  type: TODO_EDIT,
  id,
  todo
});

const TODO_DELETE = 'TODO_DELETE';
export const actionDeleteTodo = (id: number) => ({
  type: TODO_DELETE,
  id
});

const TODO_STATUS = 'TODO_STATUS';
export const actionSetStatusType = (id: number, status: ToDoStatus) => ({
  type: TODO_STATUS,
  id,
  status
});

Reducer

reducer是干啥的,很简单,就是将action所响应的改变发送给store。reducer里具体实现了如何根据action的状态改变来更新state。
Talk is cheap,show you the example:

const todoList = (state: IReduxState['todoList'] = [], action: { type: string; } & any) => {
  switch (action.type) {
    case 'TODO_ADD':
      return [
        ...state,
        {
          id: action.id,
          title: action.todo.title,
          text: action.todo.text,
          createdTime: String(new Date()),
          expiredTime: action.todo.expiredTime,
          emailAddress: action.todo.emailAddress,
          status: ToDoStatus.New,
        }
      ]
    case 'TODO_EDIT':
      return state.map(todo =>
        (todo.id === action.id)
          ? {
            id: todo.id,
            title: action.todo.title,
            text: action.todo.text,
            createdTime: todo.createdTime,
            expiredTime: action.todo.expiredTime,
            emailAddress: action.todo.emailAddress,
            status: action.todo.status, 
          }
          : todo
      )
    case 'TODO_DELETE':
      return state.filter(todo => todo.id != action.id)
    case 'TODO_STATUS':
      return state.map(todo =>
        (todo.id === action.id)
          ? { ...todo, status: action.status }
          : todo
      )
    default:
      return state
  }
}

我这里给出的一个完整的reducer是完全相对应上面的action。
我怕有朋友会疑惑,这里我说明一个东西:
文中所说的state既是reducer的参数,也是store里的部分数据。而我所说的action的状态是指在reducer里根据不同的action.type来执行不同的更新state的逻辑。
这里再补充一个store与reducer的关系:store的数据储层结构与reducer一一对应。
这是我项目里的store:


export type IReduxState = {
  todoList: Array<IToDo>;
  filterStatus: FilterStatus;
  pageStatus: PageStatus;
  id: number;
}

这是我项目里的最外层reducer:

const todoApp = combineReducers({
  todoList,
  filterStatus,
  pageStatus,
  id,
});

每一个store分支都有对应的reducer,所以所有的state的修改都是在reducer内进行。

Redux的三大核心之间的关系

我以addTodo的操作流程为示例来讲述store,action以及reducer三者之间的关系。
首先由外界发出一个dispatch(actionAddTodo(todo))来告知store要更新数据(注意,此action是携带有todo这个数据),然后reducer根据此action的type知道是addTodo所以就执行’TODO_ADD’的逻辑来更改store里的数据。

react与redux配合使用的流程原理

我们知道react的最核心部分就是组件和每个组件里面的参数props。宏观来看,react根据redux数据render出页面,当要更新数据时,react通知redux更新自己的数据,然后因为redux数据的改变,react所render出的页面也会发生变化。
在redux教程中有一个完整的react与redux结合使用的小案例,大家可以参看着学习。
下面我仍以addTodo功能的实现来讲解react与redux的结合使用。
(我给出的案例功能更强大并且使用的是typescipt语言)
addTodo页面:

import * as React from 'react'
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { actionSetPageType, actionAddTodo } from '../actions/actions';
import { PageStatus, ToDoStatus } from '../interfaces/interfaces';

type AddProps = {
  dispatch?: Dispatch;
}

@(connect() as ClassDecorator)
export default class AddTodo extends React.Component<AddProps> {
  state = {
    title: '',
    text: '',
    expiredTime: '',
    emailAddress: ''
  }
  private jumpToAppPage = () => {
    this.props.dispatch(actionSetPageType(PageStatus.App));
  }

  private changeValue = (e: React.ChangeEvent<HTMLInputElement>) => {
    switch (e.target.name) {
      case 'title':
        this.setState({ title: e.target.value });
        break;
      case 'text':
        this.setState({ text: e.target.value });
        break;
      case 'expiredTime':
        this.setState({ expiredTime: e.target.value });
        break;
      case 'emailAddress':
        this.setState({ emailAddress: e.target.value });
        break;
      default:
        break;
    }
  }

  private createTodo = () => {
    const todo = {
      id: 0,
      title: this.state.title,
      text: this.state.text,
      createdTime: '0000',
      expiredTime: this.state.expiredTime,
      emailAddress: this.state.emailAddress,
      status: ToDoStatus.New
    };
    this.props.dispatch(actionAddTodo(todo));
    this.jumpToAppPage();
  }

  render() {
    return (
      <div>
        <h3>Add</h3>
        <form action="javascript:void(0)" onSubmit={this.createTodo}>
          <label htmlFor="">Title</label>
          <input type="text" value={this.state.title} name='title' onChange={this.changeValue} />
          <br />
          <label htmlFor="">Text</label>
          <input type="text" value={this.state.text} name='text' onChange={this.changeValue} />
          <br />
          <label htmlFor="">ExpiredTime</label>
          <input type="text" value={this.state.expiredTime} name='expiredTime' onChange={this.changeValue} />
          <br />
          <label htmlFor="">EmailAddress</label>
          <input type="text" value={this.state.emailAddress} name='emailAddress' onChange={this.changeValue} />
          <br />
          <input type='submit' value='Create' />
        </form>
        <a href="javascript:void(0)" onClick={this.jumpToAppPage}>Back to List</a>
      </div>
    )
  }
}

此页面由react组件所构成,当页面触发form表单的onSubmit事件时,store会发送dispatch一个action来告知要更新数据。
然后紧接着进行上述的三大关系的流程直至更新store数据,最后由于store数据更新,react所render的页面也会变化。
todoList页面代码:

import * as React from 'react'
import { IReduxState, FilterStatus, ToDoStatus, PageStatus } from '../interfaces/interfaces';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { actionSetPageType, actionDeleteTodo, actionJumpPageId } from '../actions/actions';


const mapStateToProps = (state: IReduxState) => {
  return {
    todoList: state.todoList,
    status: state.filterStatus
  }
}

type TodoListProps = {
  todoList?: IReduxState['todoList'];
  status?: FilterStatus;
  dispatch?: Dispatch;
};
@(connect(mapStateToProps) as ClassDecorator)
export default class TodoList extends React.Component<TodoListProps> {
  private getVisibleTodoS = () => {
    switch (this.props.status) {
      case FilterStatus.New:
        return this.props.todoList.filter(todo => todo.status === ToDoStatus.New);
      case FilterStatus.Done:
        return this.props.todoList.filter(todo => todo.status === ToDoStatus.Done);
      case FilterStatus.Expired:
        return this.props.todoList.filter(todo => todo.status === ToDoStatus.Expired);
      case FilterStatus.All:
      default:
        return this.props.todoList;
    }
  }

  private jumpToEditPage = (id: number) => {
    this.props.dispatch(actionJumpPageId(id));
    this.props.dispatch(actionSetPageType(PageStatus.Edit));
  }

  private deleteHandler = (id: number) => {
    const result = window.confirm('Are you sure?');
    if (result) {
      this.props.dispatch(actionDeleteTodo(id));
    }
  }

  render() {
    const todoList = this.getVisibleTodoS();
    return (
      <table>
        <thead>
          <th>Id</th>
          <th>Title</th>
          <th>Text</th>
          <th>CreatedTime</th>
          <th>ExpiredTime</th>
          <th>EmailAddress</th>
          <th>Status</th>
          <th></th>
        </thead>
        <tbody>
          {todoList.map(todo => (
            <tr>{
              Object.values(todo).map(value =>//TODO status
                <td>{value}</td>
              )
            }
              <td>
                <a href="javascript:void(0)" onClick={() => {
                  return this.jumpToEditPage(todo.id);
                }}>Edit</a>
                {" | "}
                <a href="javascript:void(0)" onClick={() => {
                  return this.deleteHandler(todo.id);
                }}>Delete</a>
              </td>
            </tr>
          ))}
        </tbody>
      </table >
    )
  }
}

结语

其实只要我们弄清楚了react以及redux分别的作用领域,那么将它俩结合在一起使用也就不难。
如果有对此知识点不懂的地方欢迎评论区留言,我看到消息后会及时答复。
最后,由于此项目代码比较多,完整的代码我放在了github上,有兴趣的朋友可以自行下载使用。
在bash命令行中输入下列代码即可运行项目:

npm run dev

源码链接:https://github.com/rookieery/TodoListApp

本文地址:https://blog.csdn.net/asd0356/article/details/107596557