redux&react-redux(二)

简介: redux&react-redux(二)

4、一个简单的todolist案列(包含数据持久化)


4.0、redux&react-redux 项目结构

store
  index.js 创建一个store容器
  views
  Lists——>这个名是看文件,语义化就好了
    redux 
    - Actions.js   返回一个或多个动作对象,一般为`{type:'',data:''}`
    - ActionsTypes.js   返回一个或多个常量,用做Actions和Reducer的type值
    - Reducer.js    返回一个纯函数,用于处理动作对象
    index.js    将actions和reducer函数集中导出(方便管理)
    index.jsx    容器组件和UI组件的结合体


数据持久化看src/store/index.js 、 src/router.js


4.1 src/store/index.js

此文件主要就是创建一个仓库

将需要用到的reducer文件引入

从本地存储中取值,放进createStore的第二个参数,初始值的作用

import { createStore, combineReducers,applyMiddleware } from 'redux';
import thunk = 'react-thunk' //支持异步
import { reducer as lists } from '../views/Lists/_index.js'
const reducer = combineReducers({
  lists
})
let initList = JSON.parse(localStorage.getItem("LIST")) || [];
export default createStore(reducer,initList,applyMiddleware(thunk));


4.2 src/router.js

此文件主要就是做一个根组件

通过provider向下传递store

通过subscrbe方法订阅store

getState方法获取store的值存入本地

import React from 'react';
import App from './App';
import { Provider } from 'react-redux';
import Store from './store'
const StoreToken = Store.subscribe(() => {
  // Store.getState()
  // console.log(Store.getState())
  window.localStorage.setItem("LIST", JSON.stringify(Store.getState()))
})
//StoreToken() 这样可以取消订阅
const Router = () => {
  return (
    <div>
      <Provider store={Store}>
        <App />
      </Provider>
    </div>
  )
}
export default Router


4.3 src/List/redux/actions.js

此文件主要是返回一个action动作对象

action动作对象必须要有一个type属性

import * as actiontypes from './actionTypes';
export const addList = (data) => ({ type: actiontypes.ADDList, data })
export const delList = (data) => ({ type: actiontypes.DELLIST, data })


4.4 src/List/redux/actionTypes.js

此文件主要是返回一个常量,目的是防止出现字母错误(默认是大写)

export const ADDList = "ADDLIST";
export const DELLIST = "DELLIST";


4.5 src/List/redux/reducer.js

此文件返回一个纯函数,用于接收dispatch传来的action,进行处理之后返回store

默认注入两个参数(preState,action)

preState需要设置初始值

reducer被第一次调用时,是store自动触发的,传递的preState是undefined

必须要有默认返回值

import * as actionTypes from './actionTypes';
const reducer = (preState = [], action) => {
  const { type, data } = action;
  switch (type) {
    case actionTypes.ADDList:
      const result = [
        data,
        ...preState
      ]
      console.log(result)
      return result
    case actionTypes.DELLIST:
      preState.splice(data, 1)
      return [...preState]
    default:
      return preState
  }
}
export default reducer


4.6 src/List/_index.js

汇总action和reducer方便管理

actions文件只有一个

reducer文件或许会有多个

import * as actions from './redux/actions';
import reducer from './redux/reducer';
export { actions, reducer }


4.7-1 src/List/_index.js (类组件写法)

类组件中获取cannect中函数映射的值和函数都是通过props拿到的

import React,{Component} from 'react';
import { connect } from 'react-redux';
import * as actions from './redux/actions';
class View extends Component{
  // 渲染函数
  rLsits = () => {
    let { lists } = this.props;
    return lists.map((value, index) => (
      <li key={index}>{value} <button onClick={()=>{this.delfn(index)}}>删除</button></li>
    ))
  }
    // 添加数据
  send = () => {
    let val = this.inp.value;
    this.props.addLists(val)
    this.inp.value=""
  }
   // 删除数据
   delfn = (index) => {
     this.props.delLists(index)
  }
  render() {
    return (
      <div>
        <h2>这是一个class类组件操作数组数据的例子</h2>
        <input ref={value=>this.inp=value} type="text" />
        <button onClick={()=>{this.send()}}>发送</button>
        {this.rLsits()}
      </div>
    )
  }
}
// 写法一  mapDispatchToProps是一个对象
export default connect(
  state => ({ lists: state.lists }),
  {
    addLists: actions.addList,
    delLists: actions.delList
  }
)(View)
// 写法二   mapDispatchToProps是一个函数
// export default connect(
//   state => ({ lists: state.lists }),
//   (dispatch, ownProps) => ({
//     addLists: data => { dispatch(actions.addList(data)) },
//     delLists: data => { dispatch(actions.delList(data)) }
//   })
// )(View)
// 写法三   mapDispatchToProps为null
// 需要在UI组件内通过this.props.dispath传递action动作对象
// export default connect(
//   state => ({ lists: state.lists }),
//   null
// )(View)


4.7-2 src/List/_index.js (函数组件写法)

函数组件的值是通过useSelector拿到的

函数组件的dispatch是通过useDispatch 拿到的

import React,{useRef} from 'react';
import { useSelector, useDispatch } from 'react-redux';
import * as actions from './redux/actions'
const View = () => {
  let inp = useRef();
  const state = useSelector(state=>state)
  const dispath = useDispatch()
  const rLsits = () => {
    console.log('我执行了')
    return state.lists.map((value, index) => (
      <li key={index}>{value} <button onClick={()=>{delLists(index)}}>删除</button></li>
    ))
  }
  // 添加数据
  const send = () => {
    let val = inp.current.value;
    dispath(actions.addList(val))
    inp.current.value=""
  }
  // 删除数据
  const delLists = (index) => {
     dispath(actions.delList(index))
  }
  return (
    <div>
      <h2>这是一个函数组件操作数组数据的例子</h2>
      <input ref={inp} type="text" />
      <button onClick={send}>发送</button>
      {rLsits()}
    </div>
  )
}
export default View;


【补】纯函数


一类特别的函数:只要是同样的输入(实参),必定得到同样的输出(返回)

必须遵守以下一些约束

不得改写数据

不会产生任何副作用,例如网络请求,输入和输出设备

不能调用Date.now()或者Math.random()等不纯的方法

相关文章
|
1月前
|
存储 JavaScript 前端开发
掌握现代Web开发的基石:深入理解React与Redux
【10月更文挑战第14天】掌握现代Web开发的基石:深入理解React与Redux
31 0
|
30天前
|
存储 JavaScript 前端开发
React中使用redux
【10月更文挑战第15天】
30 3
|
1月前
|
存储 JavaScript 前端开发
如何使用React和Redux构建现代化Web应用程序
【10月更文挑战第4天】如何使用React和Redux构建现代化Web应用程序
|
1月前
|
JavaScript 前端开发
使用 React 和 Redux 构建动态图表应用
【10月更文挑战第3天】使用 React 和 Redux 构建动态图表应用
|
1月前
|
JavaScript 前端开发
使用 React 和 Redux 构建一个计数器应用
【10月更文挑战第3天】使用 React 和 Redux 构建一个计数器应用
|
1月前
|
存储 JavaScript 前端开发
|
1月前
|
前端开发 JavaScript 网络架构
实现动态路由与状态管理的SPA——使用React Router与Redux
【10月更文挑战第1天】实现动态路由与状态管理的SPA——使用React Router与Redux
32 1
|
3月前
|
存储 JavaScript 前端开发
React中使用redux
React中使用redux
135 56
|
1月前
|
前端开发 JavaScript
深入理解前端状态管理:React、Redux 和 MobX
【10月更文挑战第7天】深入理解前端状态管理:React、Redux 和 MobX
38 0
|
3月前
|
存储 JavaScript 前端开发
react redux 实现原理
【8月更文挑战第29天】react redux 实现原理
25 4