入门 redux 、react-redux

148 阅读4分钟

一、区别

redux:  第三方数据状态管理的库

react-redux: 封装了 redux 的一些操作,使用更方便

二、redux 基本使用

1、安装

npm i redux -S

2、了解 redux 中的常见概念

  1. state: 存储 共享 store 数据 的变量
  2. action: 一个对象,表示要 改变 store 数据的操作,类似 { type: 'ADD', payload: '参数' }
  3. store.getState(): 获取存储在 store 中的数据
  4. store.dispatch(): 执行一个 改变 store 共享数据 操作,里面传 action 这个对象
  5. store.subscribe(): 在组件中 监听 store 共享数据 变化

点击下载项目 ,直接本地运行

三、redux 项目demo

*1. 实现效果 增加的数据存入通过 redux 来存储,点击按钮 添加数据,并在组件中 获取数据列表, 并可点击进行 数据删除

image.png

2. 项目目录

image.png

3. 各文件代码

  1. reduxDemo.jsx 组件文件
import React from "react";

// 引入 定义好的 store
import store from "../redux-store";
import {
  changeInputAction,
  addItemAction,
  deleteItemAction,
} from "../redux-store/actionCreator";

export default class ReduxDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '测试',
    }

    // 监听变化,更新视图 
    // store.subscribe(this.updateList)
  }

  // 更新视图
  updatePage = () => {
    // store.getState() 返回一个对象,将数据保存到 state
    this.setState({
      list: store.getState()?.list
    })
  }
  

  componentDidMount() {
    // 监听订阅,更新视图
    let unsubscribe = store.subscribe(this.updatePage);
    this.setState({
      unsubscribe,
    });
  }

  componentWillUnmount() {
    // 移除订阅
    this.state.unsubscribe();
  }

  // 输入框改变
  inputChange = (e) => {
    const changeAction = changeInputAction(e.target.value);
    store.dispatch(changeAction);
  };

  // 添加到 list
  add = () => {
    const addAction = addItemAction();
    if (store.getState()?.inputVal) {
      store.dispatch(addAction);
    }
  };

  // 删除
  deleteItem = (index) => {
    const deleteAction = deleteItemAction(index);
    store.dispatch(deleteAction);
  };

  render() {
    return (
      <div>
        <div>redux</div>
        <input
          value={store.getState()?.inputVal || ''}
          onChange={this.inputChange}
          type="text"
        />
        <button onClick={this.add}>增加</button>
        <ul>
          {/* 也可直接通过 store.getState() 去使用 */}
          {/* {store.getState()?.list?.map((item, index) => { */}
          {this?.state?.list?.map((item, index) => {
            return (
              <button onClick={()=>{
                this.deleteItem(index)
              }} key={index}>
                {item}
              </button>
            );
          })}
        </ul>
      </div>
    );
  }
}

2.redux-store 文件夹下的 index.js ( store 的入口文件 )

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from 'redux-logger';
import thunk from 'redux-thunk'

// 引入定义的 reducer 纯函数
import { reducer } from './reducer';

// 加入中间件,可打印 store 的更新变化
const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk, logger)));

// 启用 react-redux 浏览器扩展 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 
// const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());


export default store;

3.redux-store 文件夹下的 reducer.jsx ( 状态处理器函数,根据不同 action类型 获取最新的 state 对象, 并返回它 )

import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM } from "./actionTypes";

// 纯函数, 根据不同的 action 返回新的 state
export const reducer = (state = { inputVal: 0, list: [] }, action) => {
  if (action.type === CHANGE_INPUT) {
    return {
      ...state,
      inputVal: action.value
    }
  }

  if (action.type === ADD_ITEM) {
    let newState = JSON.parse(JSON.stringify(state));
    newState.list?.push(newState.inputVal);
    newState.inputVal = ""; // 清空输入框
    return newState;
  }

  if (action.type === DELETE_ITEM) {
    let newState = JSON.parse(JSON.stringify(state));
    newState.list.splice(action.index, 1);
    return newState;
  }
};

4.redux-store 文件夹下的 actionTypes.jsx ( 定义的 action 类型,用常量定义 )

// 定义常量
export const CHANGE_INPUT = 'changeInput';
export const ADD_ITEM = 'addItem';
export const DELETE_ITEM = 'deleteItem';

5.redux-store 文件夹下的 actionCreator.jsx ( 根据 action 类型,生成不同的 action 对象 )

// 创建 action 对像的方法

import { CHANGE_INPUT, ADD_ITEM, DELETE_ITEM } from "./actionTypes";

export const changeInputAction = (value)=> {
  return {
    type: CHANGE_INPUT,
    value
  }
}

export const addItemAction = () => {
  return {
    type: ADD_ITEM
  }
}

export const deleteItemAction = (index) => {
  return {
    type: DELETE_ITEM,
    index
  }
}

6.根 index.js 文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import { Provider } from 'react-redux';
import store from './redux-store';

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

7.根 App.js 文件

import ReduxDemo from './redux-demo/reduxDemo';
import ReactReduxDemo from './react-redux-demo/reactReduxDemo';
import './App.css'

function App() {
  return (
    <div className="App">
      <ReduxDemo />
        
      <ReactReduxDemo />
    </div >
  );
}

export default App;

四、redux + react-redux 项目demo

1、安装

 npm i redux react-redux -S

2、实现效果 (和上面一致)

image.png

3.目录

image.png

4. 各文件代码

  1. reactReduxDemo.jsx 组件文件
import React from "react";
import { connect } from "react-redux";
import Son from './son';

import {
  changeInputAction,
  addItemAction,
  deleteItemAction,
} from "../react-redux-store/actionCreator";

class ReactReduxDemo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  // 输入框改变
  inputChange = (e) => {
    // const changeAction = changeInputAction(e.target.value);
    // store.dispatch(changeAction);

    this.props.customChangeInput(e.target.value);
  };

  // 添加到 list
  add = () => {
    // const addAction = addItemAction();
    // if (store.getState()?.inputVal) {
    //   store.dispatch(addAction);
    // }
    if(this.props.displayInputVal) {
      this.props.customAddItem();
    }
  };

  // 删除
  deleteItem = (index) => {
    // const deleteAction = deleteItemAction(index);
    // store.dispatch(deleteAction);
    this.props.customDeleteItem(index)
  };

  render() {
    return (
      <div>
        <div>react-redux</div>
        <input
          value={this.props?.displayInputVal || ''}
          onChange={this.inputChange}
          type="text"
        />
        <button onClick={this.add}>增加</button>
        <ul>
          {this.props?.displayList?.map((item, index) => {
            return (
              <button onClick={()=>{
                this.deleteItem(index)
              }} key={index}>
                <div>{item}</div>
              </button>
            );
          })}
        </ul>

        {/* Son组件 */}
        <Son />
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    displayInputVal: state?.inputVal,
    displayList: state?.list,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    customChangeInput: (inputVal) => {
      // 调用 dispatch
      dispatch(changeInputAction(inputVal));
    },
    customAddItem: () => {
      // 调用 dispatch
      dispatch(addItemAction());
    },
    customDeleteItem: (deleteIndex) => {
      dispatch(deleteItemAction(deleteIndex));
    },
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(ReactReduxDemo);
  1. son.jsx 组件
import React from 'react';

import { connect } from 'react-redux';
import {
  deleteItemAction,
} from '../react-redux-store/actionCreator'


class Son extends React.Component {
  // 删除
  deleteItem = (index) => {
    this.props.customDeleteItem(index)
  }
  render() {
    return (
      <div>
        <h3>子组件展示</h3>
        <div>
          {this.props?.displayList?.map((item, index) => {
            return (
              <button onClick={()=>{
                this.deleteItem(index)
              }} key={index}>
                <div>{item}</div>
              </button>
            );
          })}
        </div>
      </div>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    displayList: state?.list
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    customDeleteItem: (deleteIndex)=> {
      dispatch(deleteItemAction(deleteIndex))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Son)
  1. react-redux-store 和 redux-store中的四个文件一致
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import logger from 'redux-logger';
import thunk from 'redux-thunk'

// 引入定义的 reducer 纯函数
import { reducer } from './reducer';

// 加入中间件,可打印 store 的更新变化
// const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk, logger)));

// 启用 react-redux 浏览器扩展 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() 
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());


export default store;

五、主要区别点

  1. redux 需要在组件中调用 store.subscribe() 来监听 数据变化, 而 react-redux 有 给根组件 提供 Provider ,使得所有组件 可直接获取到 store 中的最新数据
import { Provider } from 'react-redux';
<Provider store={store}>
  <App />
</Provider>
  1. react-redux 直接通过 connect 函数包裹 自定义的组件, 在 mapStateToPropsmapDispatchToProps 中处理后,可直接在组件中 通过 this.props.变量名/方法名 获取 store 中的变量,执行更新(派发)操作
const mapStateToProps = (state) => {
  return {
    displayInputVal: state?.inputVal,
    displayList: state?.list,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    customChangeInput: (inputVal) => {
      // 调用 dispatch
      dispatch(changeInputAction(inputVal));
    },
    customAddItem: () => {
      // 调用 dispatch
      dispatch(addItemAction());
    },
    customDeleteItem: (deleteIndex) => {
      dispatch(deleteItemAction(deleteIndex));
    },
  };
};
  
// 通过 connect 连接
export default connect(mapStateToProps, mapDispatchToProps)(ReactReduxDemo);