DDR爱好者之家 Design By 杰米

本文实例为大家分享了react用Redux中央仓库实现一个todolist的具体代码,供大家参考,具体内容如下

react用Redux中央仓库实现一个todolist

Redux简单介绍

Redux是一个用来管理管理数据状态和UI状态的JavaScript应用工具。随着JavaScript单页应用(SPA)开发日趋复杂,JavaScript需要管理比任何时候都要多的state(状态),Redux就是降低管理难度的。(Redux支持React,Angular、jQuery甚至纯JavaScript)

Redux Dev Tools插件 Redux调试工具 谷歌商店下载

redux三个坑:

store仓库必须是唯一的,多个store是坚决不允许,只能有一个store空间

只有store能改变自己的内容,Reducer不能改变

Reducer必须是纯函数

Redux-thunk这个Redux最常用的插件:

在Dispatch一个Action之后,到达reducer之前,进行一些额外的操作,就需要用到middleware(中间件)

在实际工作中你可以使用中间件来进行日志记录、创建崩溃报告,调用异步接口或者路由

npm install --save redux-thunk

第一步 仓库 在store文件夹下新建index.js

//applyMiddleware,compose是为了使用下面两个插件
import {createStore,applyMiddleware,compose} from 'redux' //引入redux
import thunk from 'redux-thunk' //引入redux中间件插件
import reducer from './reducer'  //引用reducer中的数据
 
//浏览器安装的仓库插件 调试面板
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ "htmlcode">
import {ADD_ITEM , DELETE_ITEM , GET_LIST} from './actionTypes' //定义type类型的js文件
 
const defaultState = {
  value:'sss',
  list:[]  //后端获取的列表数据放在这里
}
 
// state: 指的是原始仓库里的状态。
// action: 指的是action新传递的状态。
export default (state = defaultState,action)=>{
  // console.log(state)
  //Reducer里只能接收state 不能改变state
  // if(action.type ==="changeInput"){
  //   let newState = JSON.parse(JSON.stringify(state)) //深拷贝state的值 转成字符串 赋值给一个变量
  //   newState.value = action.vlaue //改变placeholder的值等于用户输入的值
  //   return newState //将新state return出去
  // }
  //增加
  if(action.type === ADD_ITEM ){ //根据type值,编写业务逻辑
    let newState = JSON.parse(JSON.stringify(state)) 
    newState.list.push(action.value) //用户输入的新内容push新的内容到列表中去
    console.log(action)
    newState.value = '' //增加后清空
    return newState
  }
 
  //删除
  if(action.type === DELETE_ITEM ){ 
    let newState = JSON.parse(JSON.stringify(state)) 
    newState.list.splice(action.index,1) //删除数组中对应的值
    return newState
  }
 
   //后端获取数据 传递给中央仓库做处理
   if(action.type === GET_LIST ){ 
    let newState = JSON.parse(JSON.stringify(state)) 
    newState.list =action.data
    return newState
  }
  return state
}

actionTypes.js   集中管理页面reducer的type类型

//集中管理页面reducer的type类型
 
export const ADD_ITEM = "addItem"  //定义常量一般用大写
export const DELETE_ITEM = "deleteItem" 
export const GET_LIST = "getListAction" 

actionCreators.js  封装组件的action

//封装组件的action
import {ADD_ITEM , DELETE_ITEM ,GET_LIST} from './actionTypes' //定义type类型的js
import axios from 'axios'
 
//组件addItem里的action type已经封好 所以把value作为参数用箭头函数(value)=>传进来即可 
 
//增加数据
export const addItem = (value)=>({
  type:ADD_ITEM,
  value
})
 
//删除数据
export const deleteItem = (index)=>({
  type:DELETE_ITEM,
  index
})
 
//获取数据
export const getListAction = (data)=>({
  type:GET_LIST,
  data
})
 
export const getTodoList = () =>{
  return (dispatch)=>{
    axios.get('https://www.easy-mock.com/mock/5d63d7ca5774121e1a634378/demo1/demo1') 
    .then((res)=>
    {
      const data = res.data.data;
      const action = getListAction(data)
      dispatch(action)  //将action这个值传给仓库
    })
    .catch((error)=>{
      console.log(error)
    })
  }
}

TodoList.js  组件js部分

import React, { Component } from 'react';
import TodoListUi from './TodoListUi' //组件UI部分
import store from '../store/index' //组件中获得store中的数据
//import {ADD_ITEM , DELETE_ITEM} from '../store/actionTypes' //定义type类型的js 为了更方便检查错误 写错会报错
import { addItem,deleteItem,getTodoList } from '../store/actionCreators' //封装的action
 
 
//用reducer写todolist 调用中央仓库
 
class TodoList extends Component {
  constructor(props){
    super(props)
    // console.log(store.getState()) //getState方法取出仓库的值
    this.state = store.getState() //将组件state数据赋值给仓库数据
    this.changeInputVlaue = this.changeInputVlaue.bind(this) //给方法做this绑定
    this.storeChange = this.storeChange.bind(this)
    this.clickBtn = this.clickBtn.bind(this)
    this.deleteItem = this.deleteItem.bind(this)
    store.subscribe(this.storeChange) //订阅模式 改变数据时同步让仓库中的数据改变
  }
  render() { 
    return ( 
      <TodoListUi
        value={this.state.value}
        changeInputVlaue={this.changeInputVlaue}
        clickBtn={this.clickBtn}
        list={this.state.list}
        deleteItem = {this.deleteItem}
      ></TodoListUi>
     );
  }
 
  componentDidMount(){
    // axios.get('https://www.easy-mock.com/mock/5d63d7ca5774121e1a634378/demo1/demo1') 
    //   .then((res)=>
    //   {
    //    const data = res.data.data;
    //    const action =getListAction(data) //将取到的数据封入action
    //    store.dispatch(action) //传递给reducer
    //   })
    //   .catch((error)=>{
    //     console.log(error)
    //   })
    const action = getTodoList() //使用中间件获取数据
    store.dispatch(action) //传给仓库
  }
  //用户输入的值传给仓库 要通过dispatch()方法传递给store
  //Action就是一个对象,这个对象一般有两个属性,第一个是对Action的描述,第二个是要改变的值。
  //之前注销的方法,在reducer里深拷贝完state里面的数据,无法同步将用户输入赋值给state
  changeInputVlaue(e){
    this.setState({
      value:e.target.value //将用户输入的value绑定给仓库中的value,监听用户输入
    })
    // const action = {
    //   type:'changeInput', // 名字
    //   value:e.target.value //值
    // }
    // store.dispatch(action)
  }
 
  //state和组件的值同步互相改变
  storeChange(){
    this.setState(store.getState()) 
  }
 
  //增加 因为list数据存在中央仓库里 所以要做的是 将组件数据传给仓库 改变仓库数据后 再返回给组件展示
  clickBtn(){
    // console.log(this.state.value)
    // const action = { 
    //   type:ADD_ITEM,
    //   value:this.state.value //获取到用户value,用于push
    // }
    const action = addItem(this.state.value);
    store.dispatch(action)
  }
  //删除
  deleteItem(index){
    // console.log(index)
    // const action = {
    //   type:DELETE_ITEM,
    //   index  //index传过去用于删除
    // }
    const action =deleteItem(index)
    store.dispatch(action)
  }
}
export default TodoList;

TodoListUi.js 组件UI部分抽离成子组件

//此文件用于视图和逻辑的分离
import React from 'react';
import 'antd/dist/antd.css'  //引入Ant Design UI库
import { Input ,Button,List} from 'antd'  //引入input组件
 
//无状态组件 提高性能 将组件改造成函数
const TodoListUi = (props)=>{
  return ( 
    <div style={{margin:"100px"}}>
      <div>
        <Input
        style={{ width:"250px",marginRight:"20px"}}
        onChange={props.changeInputVlaue}
        value={props.value}
        />
        <Button type='primary' onClick={props.clickBtn}>增加</Button>
      </div>
      <div style={{margin:"10px",width:"300px"}}>
      <List
          bordered //加边框
          dataSource={props.list} //渲染什么数据
          renderItem={(item,index)=>(<List.Item onClick={()=>{props.deleteItem(index)}}>{item}</List.Item>)} //每项
        /> 
      </div>
    </div>
   );
}
 
//改造前组件 上边需要从react引入Component
// class TodoListUi extends Component {
//   state = { }
//   render() { 
//     return ( 
//       <div style={{margin:"100px"}}>
//         <div>
//           <Input
//           style={{ width:"250px",marginRight:"20px"}}
//           onChange={this.props.changeInputVlaue}
//           value={this.props.value}
//           />
//           <Button type='primary' onClick={this.props.clickBtn}>增加</Button>
//         </div>
//         <div style={{margin:"10px",width:"300px"}}>
//         <List
//             bordered //加边框
//             dataSource={this.props.list} //渲染什么数据
//             renderItem={(item,index)=>(<List.Item onClick={()=>{this.props.deleteItem(index)}}>{item}</List.Item>)} //每项
//           /> 
//         </div>
//       </div>
//     );
//   }
// }
 
export default TodoListUi;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

DDR爱好者之家 Design By 杰米
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
DDR爱好者之家 Design By 杰米

《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线

暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。

艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。

《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。