react之redux使用、react-redux集成、异步action之redux-thunk

1 篇文章 0 订阅
1 篇文章 0 订阅

本文目的:因新公司暂无react相关项目安排,防止自己……对某些技术淡忘,所以记录下react项目部分技术要点,方便日后快速进入状态。

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

Redux 的诞生主要为了解决下面的问题:

1、复杂的数据,比如api数据、本地数据、UI数据等

2、视图和状态管理的耦合导致的状态管理失控=>解决:redux状态管理、react视图层

那么如何设计和使用redux呢?

一、Redux基本思想

store包含了state,state定义UI,UI触发动作Actions ,Actions 发送到Reducers,Reducers根绝actions的面熟将store的state进行修改.

二、redux基础(以todoList为demo)

state:redux的state是集中管理、全局唯一,不可变性

actions:描述如何修改状态,actions就是JSON对象、必须type属性,发送需要使用store.dispatch

reducer:实质是一个函数,接受state、action进行计算,落实action传递的描述

store,redux的store就是一个粘合剂,将redux中的各个部分粘合在一起

代码示例

1、定义state数据

// const initialState ={
//     filter: 'all',
//     text: '',
//     todos: []
// }

 2、添加action事件

import {ADD_TODO, TOGGLE_TODO, SET_FILTER, SET_TODO_TEXT} from "./actionTypes"

let nextTodoId = 0

//新增待办事项
export const addTodo = (text, type, id)=>({
    id: nextTodoId++,
    type: ADD_TODO,
    text
})

//更改待办事项状态
export const toggleTodo = id=>({
    type: TOGGLE_TODO,
    id
})

//设置过滤状态
export const setFilter = filter=>({
    type: SET_FILTER,
    filter
})

//设置事项文字
export const setTodoText = text=>({
    type: SET_TODO_TEXT,
    text
})

4、reducer处理action

import {ADD_TODO, TOGGLE_TODO, SET_FILTER, SET_TODO_TEXT} from "../actions/actionTypes"
const initialState ={
    filter: 'all',
    text: '',
    todos: []
}

export const todoApp = (state,action)=>{
    switch(action.type){
        case ADD_TODO: //添加待办事项
            return {
                ...state,
                todos:[
                    ...state.todos,
                    {
                        id: action.id,
                        text: action.text,
                        completed: false
                    }
                ]
            }
        case TOGGLE_TODO: //改变事项状态
            return {
                ...state,
                todos:state.todos.map(todo=>{
                    if(todo.id === action.id){
                        return {
                            ...todo,
                            completed:!todo.completed
                        }
                    }else{
                        return {
                            ...todo
                        }
                    }
                })
            }
        case SET_TODO_TEXT: //设置事项内容
            return {
                ...state,
                text:action.text
            }
        case SET_FILTER: //设置过滤状态
            return {
                ...state,
                filter: action.filter
            }
        default:
            return state;
    }
}

为了便于维护和拓展,最好拆分一下reducer,可以通过combineReducers完成

import { combineReducers } from 'redux'

import todos from './todo'
import text from './text'
import filter from './filter'

export default combineReducers({
    todos,
    text,
    filter,
})
import {SET_TODO_TEXT} from "../actions/actionTypes"
const text = (state = "",action)=>{ //此处的state非原始initalState,传递进来的是更改的文字text
    switch(action.type){
        case SET_TODO_TEXT: //添加待办事项
            return  action.text
        default :
            return state
     }
}
export default text
import { SET_FILTER } from "../actions/actionTypes"
const filter = (state = "all",action)=>{ //此处的state非原始initalState,传递进来的是todos
    switch(action.type){
        case SET_FILTER: //设置过滤状态
            return  action.filter
        default :
            return state
     }
}
export default filter
import {ADD_TODO, TOGGLE_TODO} from "../actions/actionTypes"
const todos = (state = [],action)=>{ //此处的state非原始initalState,传递进来的是todos
    switch(action.type){
        case ADD_TODO: //添加待办事项
            return  [
                        ...state,
                        {
                            text: action.text,
                            completed: false
                        }
                    ]
        case TOGGLE_TODO: //改变事项状态
            return  state.map(todo=>{
                        if(todo.id === action.id){
                            return {
                                ...todo,
                                completed:!todo.completed
                            }
                        }else{
                            return {
                                ...todo
                            }
                        }
                    })
        default :
            return state
     }
}
export default todos

3、store

通过createStore接受reducer创建store对象

store对象提供了dispatch来发送action,通过getState获取全局state,通过subscribe订阅state变化

import { addTodo, toggleTodo, setFilter, setTodoText  } from '../actions/index';
import { createStore } from 'redux'
import rootReducer from '../reducers/index'

const store = createStore(rootReducer)

//打印state
console.log(store.getState())

//订阅变化
const subscribeInfo = store.subscribe(()=>{
    console.log(store.getState())
})

//触发actions
store.dispatch(addTodo("添加第一项待办事件"))
store.dispatch(toggleTodo(0))
store.dispatch(setFilter('active'))
store.dispatch(setTodoText('添加todolist文字描述'))
//订阅
subscribeInfo()

三、react-redux集成(链接redux-state和redux-component)

react-redux库提供的功能:

1、向根组件注入Store=>Provider组件

2、链接React组件和Redux状态成=>connect

3、获取React组件所需的State和Actions=>map api

使用了redux的引入将组件分为:展示型组件(redux)和容器型组件(redux),具体区别:

重点:容器型组件读写操作均是通过redux store中进行  以及对state数据的规划

具体实现步骤:

1、创建container存储容器型组件

编写容器型组件:通过redux的connect方法,将state、action映射到组建的props中

import {connect} from 'react-redux'
import { toggleTodo } from '../actions/index' //引入action
import TodoList from '../components/TodoList'


const mapStateToProps=(state)=>({ //将redux的state映射到react的props
    todos:getVisableTodos(state.todos,state.filter), //react组件需要的todos从redux获得
})

const mapDispatcThoProps=(distapch)=>({ //将redux的action映射到react的props
    toggleTodo: id=>distapch(toggleTodo(id)) 
})

const getVisableTodos = (todos,filter)=>{
    switch(filter){
        case 'all':
            return todos
        case 'completed':
            return todos.map(todo=>todo.completed)
        case 'active':
            return todos.map(todo=>!todo.completed)
        default:
            return new Error('Unkn')
    }

}
 

//connect接受两个函数参数
export default connect(mapStateToProps,mapDispatcThoProps)(TodoList)


app.js 测试页面。

import React, { Component } from 'react'
import AddTodoContainer from '../../containers/AddTodoContainer'
import FooterContainer from '../../containers/FooterContainer'
import TodoListContainer from '../../containers/TodoListContainer'


export default class App extends Component {
    render() {
        return (
            <div>
                <AddTodoContainer></AddTodoContainer>
                <FooterContainer></FooterContainer>
                <TodoListContainer></TodoListContainer>
            </div>
        )
    }
}

todolist组件

import React, { Component } from 'react'
import Todo from './Todo'

export default class TodoList extends Component {
    render() {
        const { todos } = this.props
        return (
            <ul>
                {
                    todos.map(todo=>{
                        return <Todo key={todo.id} {...todo}></Todo>
                    })
                }
                
            </ul>
        )
    }
}

action

import {ADD_TODO, TOGGLE_TODO, SET_FILTER, SET_TODO_TEXT} from "./actionTypes"

let nextTodoId = 0

//新增待办事项
export const addTodo = (text, type, id)=>({
    id: nextTodoId++,
    type: ADD_TODO,
    text
})

//更改待办事项状态
export const toggleTodo = id=>({
    type: TOGGLE_TODO,
    id
})

//设置过滤状态
export const setFilter = filter=>({
    type: SET_FILTER,
    filter
})

//设置事项文字
export const setTodoText = text=>({
    type: SET_TODO_TEXT,
    text
})

reducers改变redux

import {ADD_TODO, TOGGLE_TODO} from "../actions/actionTypes"
const todos = (state = [],action)=>{ //此处的state非原始initalState,传递进来的是todos
    switch(action.type){
        case ADD_TODO: //添加待办事项
            return  [
                        ...state,
                        {
                            text: action.text,
                            completed: false
                        }
                    ]
        case TOGGLE_TODO: //改变事项状态
            return  state.map(todo=>{
                        if(todo.id === action.id){
                            return {
                                ...todo,
                                completed:!todo.completed
                            }
                        }else{
                            return {
                                ...todo
                            }
                        }
                    })
        default :
            return state
     }
}
export default todos

注入store

通过redux的createStore以reducers为参数创建store

通过react-redux的provider组件将store传入项目。

部分代码示例

import { createStore } from 'redux' // 引入createStore函数
import { Provider } from 'react-redux' //引入传递store组件
import rootReducer from './reducers/index' // 引入reducer

const store = createStore(rootReducer) //创建store


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

 四、异步action

异步action关键时间点,发送阶段、成功/失败阶段

处理异步action需要redux-thunk的帮助

步骤1、定义异步action

//异步请求
const fetchTodosRequest = ()=>({
    type: FETCH_TODO_REQUEST
})
const fetchTodosSuccess = (data)=>({
    type: FETCH_TODO_SUCCESS,
    data
})  
const fetchTodosFailure = (err)=>({
    type: FETCH_TODO_FAILURE,
    err
})
export const fetchTodos = ()=>{
    return (dispatch)=>{
        dispatch(fetchTodosRequest())
        return fetch('./mock/todos.json').then(res=>{
            dispatch(fetchTodosSuccess(res))
        },err=>{
            dispatch(fetchTodosFailure(err))
        })
    }
}

顺便定一下mock数据

[{
    "id":100,
    "text":"学习react100",
    "completed":false
},{
    "id":101,
    "text":"学习react101",
    "completed":false
}]

2、添加reducer部分,使其处理异步actiontype。

为了处理异步情况,添加state新变量来描述

import {ADD_TODO, TOGGLE_TODO,
    FETCH_TODO_REQUEST,
    FETCH_TODO_SUCCESS,
    FETCH_TODO_FAILURE
} from "../actions/actionTypes"
const syncInitState = {
    isFetching: false,
    error: null,
    data: []
}
const reducer = (state=syncInitState,action)=>{
    switch(action.tyoe){
        case FETCH_TODO_REQUEST:
            return {
                ...state,
                isFetching: true,
            }
        case FETCH_TODO_SUCCESS:
            return {
                ...state,
                isFetching: false,
                data: action.data
            }
        case FETCH_TODO_FAILURE:
            return {
                ...state,
                isFetching: false,
                data: action.err
            }
        default:
            return {
                ...state,
                data: todos(state.data,action)
            }
    }
}

const todos = (state = [],action)=>{ //此处的state非原始initalState,传递进来的是todos
    switch(action.type){
        case ADD_TODO: //添加待办事项
            return  [
                        ...state,
                        {
                            id: action.id,
                            text: action.text,
                            completed: false
                        }
                    ]
        case TOGGLE_TODO: //改变事项状态
            return  state.map(todo=>{
                        if(todo.id === action.id){
                            return {
                                ...todo,
                                completed:!todo.completed
                            }
                        }else{
                            return {
                                ...todo
                            }
                        }
                    })
        default :
            return state
     }
}
export default reducer

3、因为state发生了变化,所以容器型组件也要做出相应改变,原来state.todos数据变味了state.todos.data,并添加异步事件    fetchTodos: ()=>distapch(fetchTodos())

import {connect} from 'react-redux'
import { toggleTodo } from '../actions/index' //引入action
import TodoList from '../components/TodoList'


const mapStateToProps=(state)=>({ //将redux的state映射到react的props
    todos:getVisableTodos(state.todos.data,state.filter), //react组件需要的todos从redux获得
})

const mapDispatcThoProps=(distapch)=>({ //将redux的action映射到react的props
    toggleTodo: id=>distapch(toggleTodo(id)) ,
    fetchTodos: ()=>distapch(fetchTodos())

})

const getVisableTodos = (todos,filter)=>{
    switch(filter){
        case 'all':
            return todos
        case 'completed':
            return todos.map(todo=>todo.completed)
        case 'active':
            return todos.map(todo=>!todo.completed)
        default:
            return new Error('Unkn')
    }

}
 

//connect接受两个函数参数
export default connect(mapStateToProps,mapDispatcThoProps)(TodoList)


4、引入redux-thunk的thunkMiddleware 在创建store时通过redux的applyMiddleware使用,部分代码

import { createStore, applyMiddleware } from 'redux' // 引入createStore函数
import  thunkMiddle from 'redux-thunk'

const store = createStore(rootReducer,applyMiddleware(thunkMiddle)) //创建store
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/redux/App';
import reportWebVitals from './reportWebVitals';
// import store from './store/index'
import { createStore, applyMiddleware } from 'redux' // 引入createStore函数
import { Provider } from 'react-redux' //引入传递store组件
import rootReducer from './reducers/index' // 引入reducer
import  thunkMiddle from 'redux-thunk'

const store = createStore(rootReducer,applyMiddleware(thunkMiddle)) //创建store

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


// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

补充:

1、vscode react相关快捷键:

rcc=>快速创建react类

2、selector函数

添加selector函数,实现state和视图层的解耦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值