阅读 242

【React学习笔记】Redux,React-redux,Redux-thunk的使用

Redux

Redux 是一个独立的 JavaScript 状态管理库,不依赖于任何其他库

Redux的使用

import {createStore} from 'redux';

const store = createStore((state={count:1,name:'xiaoming'},action)=>{
    switch(action.type){
        case 'ADD':
            return {
                ...state,
                count:state.count+1
            }
        case 'MINS':
            return {
                ...state,
                count:state.count-1
            }
        default:
            return {
                ...state,
                count:state.count
            }
    }
})

export default store;
复制代码

createStore中传入reducer,reducer是一个函数,有两个参数state和action,通过判断action的判断来对state执行不同的操作;

Redux api

createStore(reducer, [preloadedState], enhancer); 
  - reducer (Function): 接收两个参数,分别是当前的 state 树和要处理的 action,返回新的 state 树。
  - [preloadedState] (any): 初始时的 state。 在同构应用中,你可以决定是否把服务端传来的 state 后传给它,或者从之前保存的用户会话中恢复一个传给它。如果你使用 combineReducers 创建 reducer,它必须是一个普通对象,与传入的 keys 保持同样的结构。否则,你可以自由传入任何 reducer 可理解的内容。
  - enhancer (Function): Store enhancer 是一个组合 store creator 的高阶函数,返回一个新的强化过的 store creator。这与 middleware 相似,它也允许你通过复合函数改变 store 接口。
  - 返回值 (Store): 保存了应用所有 state 的对象。改变 state 的惟一方法是 dispatch action。你也可以 subscribe 监听 state 的变化,然后更新 UI。
reducer 
  - reducer(state,action)
  
Store 
  - getState()
  - dispatch(action):dispatch传入action对象,触发reducer;
  - subscribe(listener):subscribe用来监控state的变化,返回的参数用来取消监控;
  - replaceReducer(nextReducer):replaceReducer替换reducer;

combineReducers(reducers)
  将 reducer 函数拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分

applyMiddleware(...middlewares) 中间件
复制代码

Redux三大原则

  1. 单一数据源:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store 中

  2. state是只读的:唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象

  3. 使用纯函数来执行修改

    高阶函数和纯函数

    高阶函数,至少满足下面一个条件的函数:1.接受一个或多个函数作为输入;2.输出一个函数

    纯函数,1.相同的输入永远返回相同的输出;2.不改变函数的输入值;3.不依赖外部环境状态;4.无任何副作用

reducer的拆分与合并

使用combineReducers合并reducer

import { createStore, combineReducers} from "redux";
/*
  reducer 的拆分与合并:
  action.type 在项目中时唯一的
*/

//reducer的拆分
const count = (count=1,action)=>{
  switch (action.type) {
    case "COUNT_ADD":
      return count + 1;
    case "COUNT_MINS":
      return count - 1;
    default:
      return count;
  }
}
const list = (list={
  type: "all",
  data: [],
  nub: 1
},action)=>{
  switch (action.type) {
    case "LIST_ADD":
      return {
        ...list,
        nub: list.nub + 1
      }
    case "LIST_MINS":
      return {
        ...list,
        nub: list.nub - 1
      };
    default:
      return list;
  }
}

// reducer 的合并
// const reducer = (state = {
//   count: 1,
//   list: {}
// }, action) => {
//   return {
//     count:count(state.count,action),
//     list: list(state.list,action)
//   }
// }

// reducer 的合并
const reducer = combineReducers({
  count,
  list
});

const store = createStore(reducer);

export default store;
复制代码

React-redux

react项目中的 redux 绑定库

状态绑定

将仓库(store)通过Provider组件传给App

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

ReactDOM.render(
    <Provider store={store}>
        <App></App>
    </Provider>,
    document.querySelector("#root")
);
复制代码

接收参数

  • connect
const withConnect = connect((state) => {
    const {count} = state;
    return {count};//返回值是state中要传递给组件的数据,必须是一个对象!
})

//App传下来的props通过withConnect会自动组合到state中传给App组件
export default withConnect(App);
复制代码
  • hooks
  1. useDispatch获取dispatch

  2. useStore获取store

  3. useSelector获取state

import { useDispatch, useSelector, useStore } from "react-redux"

function App(props) {
    const dispatch = useDispatch();
    const count = useSelector(state=>state.count);
    const store = useStore();
    console.log(store.getState());
    console.log(props);
    return <div>
        <p>{count}</p>
        <button onClick={() => {
            dispatch({ type: 'ADD' })
        }}>+</button>
        <button onClick={() => {
            dispatch({
                type: 'MINS'
            })
        }}>-</button>
    </div>
}

export default App;
复制代码

redux-thunk

ps:不是react-thunk !!!

使用

使用 thunk 中间件后,action可以支持两种形式: "函数" 和 "对象"

  1. 参数是对象,直接调用 reducer 修改我们的 state
  2. ,参数是函数调用该函数,并且把 dispatch 和 getState 传递我们的函数,可以在函数中,进行异步操作
import { createStore, applyMiddleware} from "redux";
import thunk from "redux-thunk";
const reducer = <你的reducer>
const store = createStore(reducer,applyMiddleware(thunk));
复制代码

异步获取数据问题

举例:根据不同的type获取cnode( cnodejs.org/api )的list数据

store.js

import { createStore, combineReducers, applyMiddleware} from "redux";
import thunk from "redux-thunk";

const list = (list={
  type: "all",
  data: [],
  loading: true
},action)=>{
  switch (action.type) {
    case "LIST_LOADING":
      return {
        ...list,
        data: [],
        loading: true
      }
    case "LIST_LOAD":
      return {
        ...list,
        data: action.data,
        loading: false
      }
    case "LIST_TYPECHANGE":
      return {
        ...list,
        type: action.dataType,
      }
    default:
      return list;
  }
}

const reducer = combineReducers({
  list
});
const store = createStore(reducer,applyMiddleware(thunk));

export default store;
复制代码

app.js

import { useEffect } from "react";
import { useSelector,useDispatch } from "react-redux";
import { getListData } from "./actions";
// ask share job good
function App() {
  const list = useSelector(state => state.list);
  const {type,data,loading} = list;
  const dispatch = useDispatch();
  useEffect(()=>{
    dispatch(getListData);
  },[type]);
  return <div>
    <button onClick={()=>{
      dispatch({
        type: "LIST_TYPECHANGE",
        dataType: "all"
      })
    }}>all</button>
    <button onClick={()=>{
      dispatch({
        type: "LIST_TYPECHANGE",
        dataType: "ask"
      })
    }}>ask</button>
    <button onClick={()=>{
      dispatch({
        type: "LIST_TYPECHANGE",
        dataType: "share"
      })
    }}>share</button>
    {loading?<div>数据更新中</div>:<ul>{
      data.map(item=><li key={item.id}>{item.title}</li>)
    }</ul>}
    
  </div>
}

export default App;
复制代码
import axios from "axios";
function getListData(dispatch, getState) {
  dispatch({
    type: "LIST_LOADING"
  });
  axios.get(`https://cnodejs.org/api/v1/topics?page=1&tab=${getState().list.type}&limit=10`).then(res => {
    dispatch({
      type: "LIST_LOAD",
      data:res.data.data
    })
  })
}
export { getListData };
复制代码
文章分类
前端
文章标签