redux的入门和使用

redux的入门使用

简介

  1. 在网上查到的各种redux的资料要么是各种复制官方文档的, 要么是讲的不明所以的
  2. 经历了这种痛苦的折磨后, 自己总算用redux写出了一个todomvc

事先准备

  1. 创建项目
  • 使用create-react-app 创建项目
  1. 需要下载的插件
  • antd ui框架
  • babel-plugin-import 模块引入插件
  • babel-plugin-transform-decorators-legacy redux的装饰器
  • react-redux 和 redux 这个不用说了
  • react-router-dom react的路由
  • redux-thunk 处理异步的redux
  • node-sass 和 sass-loader sass的插件
  1. 配置create-react-app
    // 先安装好所有默认依赖包
    yarn install

    // 开启create-react-app的配置
    yarn eject

    // 在package.json中增加redux的装饰器配置  => 在babel的配置中添加
    "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
      ]

      // 配置antd  =>  在config文件夹下的webpack.config文件的babel-loader的options里添加
      "plugins": [
         ["import", {
            "libraryName": "antd",
            "libraryDirectory": "es",
            "style": "css" // `style: true` 会加载 less 文件
         }]
       ]
      
      // 配置sass  =>  在config文件夹下的webpack.config文件的css-loader修改成
      {
        test: /\.(css|scss|sass)$/,
          use: [
            require.resolve('style-loader'),
            {
              loader: require.resolve('css-loader'),
              options: {
                importLoaders: 1,
              },
            },
            "sass-loader",
            {options.....不用修改}
          }
      }

项目结构

  ```js
      |-- src
          |-- component            // 可复用的组件
                |-- footer.js            // 底部
                |-- header.js            // 头部
                |-- main.js             // 中间主体
          |-- container            // 骨架组件
                |-- all.js            // `/all`路由下对应的显示的组件
                |-- active.js            // `/active`路由下对应的显示的组件
                |-- completed.js            // `/completed`路由下对应的显示的组件
          |-- store            // 所有的状态管理
                |-- actions            // 所有的action文件夹
                      |-- action.js            // 项目用到的action, 如果项目很大, 可以是多个action文件
                |-- reducers            // 所有的reducer文件夹
                      |-- add_reducer.js            // 项目所用到的reducer, 如果项目更大, 可以是多个
                |-- reducer.js            // 组合所有的reducer
                |-- types.js            // 定义变量, 统一管理
          |-- App.js            // 项目主骨架
          |-- app.scss            // 项目的公共样式
          |-- index.js            // 把项目部署到页面
  ```

开始项目

  1. index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import {Provider} from 'react-redux'
import thunk from 'redux-thunk'
import {createStore, applyMiddleware, compose} from 'redux'
import reducers from './store/reducer'

// 将所有的reducer注册到页面
const store = createStore(reducers, compose(
   applyMiddleware(thunk),    // 使用thunk中间件
   window.devToolsExtension ? window.devToolsExtension() : f => f      // 这个是使用调试redux的插件
))

ReactDOM.render(
   
       
   
   , document.getElementById('root')
)
  1. App.js
import React, { Component } from 'react'
import { Layout } from 'antd'
import Main from './component/main'
// 引入样式文件
import './app.scss'

class App extends Component {
  render() {
    const { Header, Footer, Content } = Layout
    return (
      
    )
  }
}

export default App
  1. main.js
import React, { Component } from 'react'
import {BrowserRouter, Route, Switch} from 'react-router-dom'
import All from '../container/all'
import Active from '../container/active'
import Completed from '../container/completed'
import MainHeader from './header'


class Main extends Component{
    render() {
        return (
            
) } } export default Main
  1. types.js
export const Add_TODO = 'ADD'   // 添加

export const COMPLET_TODO = 'COMPLETED' // 完成单条

export const COMPLET_ALL_TODO = 'COMPLET_ALL_TODO' // 完成所有

export const CLEAR_TODO = 'CLEAR'   // 清空所有完成的

export const DELETE_TODO = 'DELETE_TODO'    // 删除单条
  1. reduer.js
import {combineReducers} from 'redux'
import {add} from './reducers/add_reducer'

export default combineReducers({add})  // 如果有多个, 只要放在add后面即可组合
  1. add_reducer.js
// 这里面的逻辑不是一开始就能写好的, 是随着项目的开发而慢慢完善的
import { Add_TODO, COMPLET_TODO, COMPLET_ALL_TODO, CLEAR_TODO, DELETE_TODO } from '../types'

// 定义初始的值
const initState = [
    {
        id: 0,
        value: '',
        checked: false
    }
]

// 输出的reducer
export function add(state = initState, action){
    switch (action.type){
        // 增加操作
        case Add_TODO:
            return [
                ...state,
                {
                    id: state.reduce((maxId, todo) => Math.max(maxId, todo.id), 0) + 1,  // 此处给每条添加的数据增加id
                    value: action.payload.value,
                    checked: action.payload.checked
                }
            ]
        // 选中完成
        case COMPLET_TODO:
            state.map(v => {
                if(v.id === action.payload.id){
                    v.checked = !v.checked
                }
                return v
            })
            return [...state]
        // 全选
        case COMPLET_ALL_TODO:
            let flag = true
            flag = state.every(v => v.checked === true)
            state.map(v => {
                flag ? v.checked = false : v.checked = true
                return v
            })
            return [...state]
        // 清除所有
        case CLEAR_TODO:
            state = initState
            return [...state]
        // 删除单条
        case DELETE_TODO:
            return [...(state.filter(v => v.id !== action.payload.id))]
        default:
            return state
    }
}
  1. action.js
import { Add_TODO, COMPLET_TODO, COMPLET_ALL_TODO, CLEAR_TODO, DELETE_TODO } from '../types'

// 增加
export function addData(value){
    return {type: Add_TODO, payload: {value, checked: false} }
}

// 选中
export function completeData(id){
    return {type: COMPLET_TODO, payload: {id}}
}

// 全选
export function completeAllData(){
    return {type: COMPLET_ALL_TODO}
}

// 清除
export function clearAll(){
    return {type: CLEAR_TODO}
}

// 删除
export function deleteData(id){
    return {type: DELETE_TODO, payload: {id}}
}
  1. header.js
import React, { Component } from 'react'
import { Form, Input, Button } from 'antd'
import { connect } from 'react-redux'
import { addData, completeAllData } from '../redux/actions/action'    // 引入需要的action

// 装饰器的写法, 将action和state注册到组件
@connect(
    state => ({add: state.add}),
    { addData, completeAllData }
)


class MainHeader extends Component{
    constructor(props){
        super(props)
        this.completedAll = this.completedAll.bind(this)
    }
    completedAll(){
        if(this.props.add.length < 1) return
        this.props.completeAllData()
    }
    handleEnter(v){
        const value = v.target.value
        this.props.addData(value)
        v.target.value = ' '
    }
    render() {
        const FormItem = Form.Item
        return(
            
this.handleEnter(v)}/>
) } } export default MainHeader
  1. footer.js
import React, { Component } from 'react'
import {Link} from 'react-router-dom'
import { Form } from 'antd'
import { clearAll } from '../redux/actions/action'
import { connect } from 'react-redux'

@connect(
    state => ({add: state.add.slice(1)}),
    { clearAll }
)

class MainFooter extends Component{
    
    render() {
        const FormItem = Form.Item
        let left = 0
        this.props.add.forEach(v => {
            if(v.checked === false){
                left += 1
            }
        })

        return(
            
{left} items left All Active Completed clear completed
) } } export default MainFooter
  1. all.js
import React, { Component } from 'react'
import MainFooter from '../component/footer'
import { List, Checkbox, Icon } from 'antd'
import { connect } from 'react-redux'
import { completeData, deleteData } from '../redux/actions/action'
@connect(
    state => ({add: state.add}),
    {completeData, deleteData}
)

class All extends Component{
    constructor(props){
        super(props)
        this.state = {
            showClose: false,
            itemId: 0
        }
        this.handleCheck = this.handleCheck.bind(this)
    }
    handleCheck(id){
        this.props.completeData(id)
    }
    render() {
        // 去除第一个默认的数据
        const allData = this.props.add.slice(1)
        return (
            
{allData.length < 1 ? null : allData.map(v => { if(v.id === 0) return null return ( this.setState({showClose:true,itemId: v.id})} onMouseLeave={() => this.setState({showClose: false})}> {this.state.showClose && this.state.itemId === v.id ? this.props.deleteData(v.id) }> : ''} this.handleCheck(v.id)}> ) })}
) } } export default All
  1. active.js
import React, { Component } from 'react'
import MainFooter from '../component/footer'
import { List, Checkbox, Icon } from 'antd'
import { connect } from 'react-redux'
import { completeData, deleteData } from '../redux/actions/action'
@connect(
    state => ({add: state.add}),
    {completeData, deleteData}
)

class Active extends Component{
    constructor(props){
        super(props)
        this.handleCheck = this.handleCheck.bind(this)
    }
    handleCheck(id){
        this.props.completeData(id)
    }


    render() {
        // 获取未选中的数据
        const allData = this.props.add.slice(1).filter(v => v.checked === false)
        return (
            
{allData.length < 1 ? null : allData.map(v => { if(v.id === 0) return null return ( this.props.deleteData(v.id) }> this.handleCheck(v.id)}> ) })}
) } } export default Active
  1. completed.js
import React, { Component } from 'react'
import MainFooter from '../component/footer'
import { List, Checkbox, Icon } from 'antd'
import { connect } from 'react-redux'
import { completeData, deleteData } from '../redux/actions/action'
@connect(
    state => ({add: state.add}),
    {completeData, deleteData}
)

class Completed extends Component{
    constructor(props){
        super(props)
        this.handleCheck = this.handleCheck.bind(this)
    }
    handleCheck(id){
        this.props.completeData(id)
    }

    render() {
        // 获取选中的数据
        const allData = this.props.add.slice(1).filter(v => v.checked === true)
        return (
            
{allData.length < 1 ? null : allData.map(v => { if(v.id === 0) return null return ( this.props.deleteData(v.id) }> this.handleCheck(v.id)}> ) })}
) } } export default Completed
  • 附app.scss
html, body, #root{
    width: 100%;
    height: 100%;
}

.App{
    width: 100%;
    height: 100%;
    .ant-layout{
        width: 100%;
        height: 100%;
        .ant-layout-header{
            h2{
                color: #fff;
                text-align: center;
                height: 100%;
                font-size: 35px;
                margin: 0;
            }
        }
        .footer{
            width: 100%;
            text-align: center;
            display: block;
            color: #999;
        }
        .ant-layout-content{
            height: 80%;
            overflow: auto;
            .container{
                width: 40%;
                height: 50%;
                margin: 100px auto;
                .ant-list-item{
                    overflow: hidden;
                    position: relative;
                    .ant-list-item-meta{
                        width: 100%;
                        .ant-list-item-meta-content{
                            width: 100%;
                            .ant-list-item-meta-description{
                                width: 100%;
                                overflow: hidden;
                                text-overflow: ellipsis;
                                white-space: nowrap;
                            }
                        }
                    }
                    .ant-list-item-content{
                        position: absolute;
                        top: 12px;
                        left: 3px;
                        width: 100%;
                        i.anticon{
                            top: 5px;
                            right: 12px;
                            position: absolute;
                            cursor: pointer;
                        }
                        .ant-checkbox-wrapper{
                            position: absolute;
                            top: 0;
                            left: 0;
                        }
                    }
                }
            }
        }
        .form-footer{
            .footer-left{
                float: left;
            }
            .footer-link{
                float: left;
                margin-left: 60px;
                a{
                    margin-left: 20px;
                    display: inline-block;
                    color: #777;
                }
            }
            .footer-right{
                float: right;
                cursor: pointer;
            }
        }
    }
}

你可能感兴趣的:(redux的入门和使用)