redux的概念介绍和基础使用

12 篇文章 0 订阅

一. Redux介绍

1. 1 背景

当前端项目越来越庞大,使用到的诸如缓存数据、服务端数据、本地持久化数据也就越来越多,mode的变化会引起view的更新,而mode的来源是不确定,经常是错综复杂,甚至十分混乱的,遇到错误时很难排查和追踪。你可能使用过React中的context(上下文)把状态提升到顶层,被所有的子组件共享,这样还避免了props的层层传递。Redux也是一款类似的状态管理工具,不过它的功能更加全面,它是独立的,不仅仅可以应用在react中,还可以应用在javaScript项目中。

1.2. 核心思想

Redux的核心思想十分简单,就是一个简单的发布订阅,同时限定了只能通过dispatch(action)的方式更新数据,使数据的变化具有可预测性。

1.3 . 概念

  • store 唯一的数据存储中心,其中还包含一些封装过的方法,例如getState和subsSribe
   const store = createStore(reducer,initState);
  • action 通常是一个对象,定义要以哪种方式(reducer)改变数据
const ADD = 'ADD';
export function add(id, text) {
  return { type: ADD, id, text };
};
  • dispatch 更新数据的唯一方式
   dispatch(action);
  • reducer 定义如何改变数据,是一个纯函数
function reducer(state = {}, action) {
  ...,
  return newState;
}
  • subScribe 订阅数据的方法,数据变化时执行
store.subscribe(()=>{
  console.log(`新的值为`,store.getState());
});

1.4 Redux的三大原则

  1. 单一数据源
  2. 数据只读,只能通过dispatch的方式去更改数据
  3. reducer是一个存函数,不能带有副作用

二、基础使用

2.1 安装

yarn add redux --save

2.2 订阅数据

action.js

const ADD = 'ADD';
const REMOVE = 'REMOVE';
const SET_COMPLETE = 'SET_COMPLETE';


export function add(id, text) {
  return { type: ADD, id, text };
};

export function remove(id) {
  return { type: REMOVE, id };
};


export function setComlete(id, complete) {
  return { type: SET_COMPLETE, id, complete }
};

export default { ADD, REMOVE, SET_COMPLETE, add, remove, setComlete };

reducer.js

import actions from './action'

// 注意reducer必须是一个存函数
function AppReducer(state = {}, action) {
  const { id, text } = action;
  const newTodoList = [...state.todoList];
  switch (action.type) {
    case actions.ADD: return { todoList: [...newTodoList, { id, text, complete: false, }] };
    case actions.REMOVE: return { todoList: newTodoList.filter(t => t.id !== id) };
    case actions.SET_COMPLETE: return { todoList: newTodoList.map(t => t.id === action.id ? t : { ...t, complete: action.complete }) };
    default: return state;
  }
};
export default AppReducer;

store.js

import reducer from './reducer';
import { createStore } from 'redux';

const initState = {
  todoList:[
    {id:'1',text:'游泳',complete:false},
    {id:'2',text:'冥想',complete:false},
    {id:'3',text:'工作',complete:false},
    {id:'4',text:'午休',complete:false},
    {id:'5',text:'追番',complete:false},
  ]
}
const store = createStore(reducer,initState);

export default  store;

List.jsx // 使用redux实现一个TodoList

import { memo, useCallback, useEffect, useState } from 'react';
import { Input, Button } from 'antd';
import store from './store';
import {add, remove} from './action';

function List() {
  const [id, setId] = useState('0');

  useEffect(()=>{
    store.subscribe(()=>{
      console.log(`新的值为`,store.getState());
    });
  },[]);

  const onAdd = useCallback(() => {
    store.dispatch(add(id,`新增数据${id}`));
  }, [id]);

  const onRemove = useCallback(() => {
    store.dispatch(remove(id));
  }, [id]);

  const onInputChange = useCallback((e) => {
    setId(e.target.value);
  }, []);

  return (
    <div className="App">
      <span>id:  <Input onChange={onInputChange} value={id} type='text' /></span>
      <Button onClick={onAdd}>增加</Button>
      <Button onClick={onRemove}>删除</Button>
    </div>
  );
}

export default memo(List);

上述代码中使用subScribe函数订阅了store,当store中的数据发生变化的时候会执行回调函数
在这里插入图片描述

2.3 搭配react进行视图的渲染和更新

上述代码中我们只监听了数据的变化,但是如何将数据的变化和视图的渲染关联到一起呢?这个就是react-redux的职责了,只需要简单两个步骤就可以将redux的数据和视图关联起来。

第一步: 安装react-redux

yarn add react-redux

第二部: 改造List.jsx

// List.jsx
import { memo, useCallback, useState, useMemo } from 'react';
import { Input, Button } from 'antd';
import { add, remove } from './action';
import { connect } from 'react-redux';

// 将redux的state映射到props
const mapStateToProps = (state) => {
  return { todoList: state.todoList };
};

// 将redux的dispatch映射到props
const mapDispatchToProps = (dispatch) => {
  return {
    onAdd: (id) => dispatch(add(id, `新增数据${id}`)),
    onRemove: (id) => dispatch(remove(id)),
  }
};

// 实现一个TodoList
function List(props) {
  const [id, setId] = useState('0');

  const onInputChange = useCallback((e) => {
    setId(e.target.value);
  }, []);

  const renderList = useMemo(() => {
    return props.todoList.map(todo => {
      return <div style={{ marginTop: '20px' }} key={todo.id}>
        <div>名称:{todo.text}</div>
        <div>ID:{todo.id}</div>
        <div>状态:{todo.complete ? '完成' : '未完成'}</div>
      </div>
    })
  }, [props.todoList]);

  return (
    <div className="App" style={{ textAlign: 'center' }}>
      <span>id:  <Input onChange={onInputChange} value={id} type='text' /></span>
      <Button onClick={() => props.onAdd(id)}>增加</Button>
      <Button onClick={() => props.onRemove(id)}>删除</Button>
      {renderList}
    </div>
  );
}

export default memo(connect(mapStateToProps, mapDispatchToProps)(List));


// App.jsx
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import store from './store';
import List from './List';

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <List />
      </Provider>
    )
  }
}
  • provider的作用是将store注入到全局,方便子组件中获取
  • connect是一个高阶组件,作为容器组件将state和dispatch注入到展示组价,connect接收mapStateToProps和mapDispatchToProps两个参数,如果不传递state默认为store中的全部数据,dispatch则为store.dispatch

三. 使用combineReducers拆分reducer

当数据过多的时候可以对reducer进行拆分,上面的例子中我们只有一个todoList,现在我们来添加一个存储用登录信息的数据。

// reducer.js
export function todoListReducer(state = [], action) {
  const { id, text } = action;
  const newTodoList = [...state];
  switch (action.type) {
    case actions.ADD: return [...newTodoList, { id, text, complete: false, }];
    case actions.REMOVE: return newTodoList.filter(t => t.id !== id);
    case actions.SET_COMPLETE: return newTodoList.map(t => t.id === action.id ? t : { ...t, complete: action.complete });
    default: return state;
  }
};

export function userInfoReducer(state = {}, action) {
  switch (action.type) {
    case actions.ADD_USERINFO: return action.userInfo;
    case actions.REMOVE_USERINFO: return {};
    default: return state;
  }
};

// store.js

import { userInfoReducer, todoListReducer } from './reducer';
import { createStore, combineReducers } from 'redux';

const initState = {
  todoList: [
    { id: '1', text: '游泳', complete: false },
    { id: '2', text: '冥想', complete: false },
    { id: '3', text: '工作', complete: false },
    { id: '4', text: '午休', complete: false },
    { id: '5', text: '追番', complete: false },
  ],
  userInfo: {},
};

const store = createStore(combineReducers({ todoList: todoListReducer, userInfo: userInfoReducer }), initState);

export default store;

下一章讲述redux中间件的使用,以及中间件的思想

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值