React-native学习-56--使用create-react-app脚手架生成项目--react-redux 入门实战

1.概述

1.1 React 与 Redux 的关系

  • react 与 redux 是没有关系的,redux 支持 react, angular, jQuery, 甚至是javascript
  • Redux 与 React 这类库搭配起来更好用

1.2 React-redux

  • react-redux 就是 Redux 官方出的用于配合 React 的绑定库
  • react-redux 能够使你的 React 组件从 Redux store 中很方便的读取数据, 并且向 store 中分发 actions 更新数据

1.3 React-Redux 中两个重要的成员

  • Provider 这个组件能够使你整个app都能获取到store中的数据

    • Provider 包裹在跟组件的最外层,使所有的子组件都可以拿到 state
    • Provider 接收 store 作为 props,然后通过 context 往下传递,这样react中任何组件都可以通过 context 获取到 store
    • 解决了容器组件可能存在很深的层级,防止一层一层去传递state
  • connect 这个方法能够使组件跟 store 来进行关联

    • Provider 内部组件如果想要使用到 state 中的数据,就必须要 connect 进行一层包裹封装(必须要被 connect 进行加强)
    • connect 就是方便我们组件能够获取到 store 中的state

2. React-Redux 基本使用

2.1 前期准备

2.1.1 使用create-react-app脚手架生成项目

npx create-react-app count-demo

2.2.2 删除无用组件,修改项目结构&配置

2.2 安装 react-redux

  • react-redux 不是 react 官方所提供,所以当我们构建 react 项目之后, 需要进行安装
yarn add react-redux
npm install react-redux --save
  • react-redux 还需要依赖于 Redux 中的 store,所以我们还需要安装 redux
yarn add redux
npm install redux --save

2.3 利用 redux 来构建 store

  • 创建 reducer/index.js 文件,构建 reducer 来响应actions
// reducer/index.js
/**
*@desc 纯函数,接收两个参数
*@paream state
*@paream action
/

export const reducer = (state, action)=> {
    return state
}
  • 创建 store/index.js 文件,通过createStore方法,把我们的reducer传入进来
// store/index.js
import { createStore } from 'redux'
import { reducer } from '../reducer'

const store = createStore(reducer)
export default store
  • 在app.js中引入 store
// app.js
import React from 'react'
import "./App.css"
// 导入我们的store
function App() {
    return <div className="App"><div/>
}

2.4构建页面

  • 实现一个可以处理加减的计数器,页面如下图所示

  • 创建一个组件,名字叫CountButton,里面放两个 button 按钮
// components/CountButton.jsx
import React from 'react'

export default function CountButton() {
  return (
    <button> +10 </button>
    <button> -2 </button>
  )
}
  • 创建另外一个组件,名字教 CountNum,里面放一个 div,用来现实数字
// components/CountNum.jsx
import React from 'react'

export default function CountNum(props) {
  return (
    <div>0</div>
  )
}
  • 在 app.js 中引入两个组件
// app.js
import React from 'react';
import './App.css';

import store from './react-redux/store'
import CountButton from './components/CountButton'
import CountNum from './components/CountNum'
function App() {
  return (
    <div className="App">
      <CountButton />
      <CountNum />
    </div>
  );
}

export default App;

2.5 action 和 reducer 改造

  • action 创建函数

    • Action 是把数据从应用传到 store 的有效载荷; 它是 store 数据的唯一来源。
    • Action 本质上是 JavaScript 普通对象。我们约定,action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作
    • Action 创建函数 就是生成 action 的方法
// actions/index.js
export const addAction = (num)=> {
  return {
    type: 'ADD_NUM',
    payload: {
      num
    }
  }
}

export const reduceAction=(num)=> {
  return {
    type: 'REDUCE_NUM',
    payload: {
      num
    }
  }
}
  • 我们的组件具有增加和减少两个功能,所以 reducer 需要根据不同的 action type 来处理不同的场景;

    • reducer 指定了应用状态的变化如何响应 actions 并发送到 store 的
    • reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
    • 保持 reducer 纯净非常重要。永远不要在 reducer 里做这些操作:

      • 修改传入参数;
      • 执行有副作用的操作,如 API 请求和路由跳转;
      • 调用非纯函数,如 Date.now() 或 Math.random()。

注意:

不要修改 state。 使用 Object.assign() 新建了一个副本。不能这样使用 Object.assign(state, { visibilityFilter: action.filter }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以开启对 ES7 提案对象展开运算符的支持, 从而使用 { ...state, ...newState } 达到相同的目的。
在 default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state。

// reducer/index.js
const initialState = {
  count: 0
}
export const reducer = (state = initialState, action)=> {
  switch (action.type) {
    case 'ADD_NUM':
      return {
        ...state,
        count: state.count + action.payload.num
      }
    case 'REDUCE_NUM':
      return {
        ...state,
        count: state.count - action.payload.num
      }
    default:
      return state
  }
}

2.6 引入 Provider 组件

  • 在 app.js 中导入 Provider 组件
import { Provider } from 'react-redux'
  • 利用 Provider 组件将我们整个结构进行包裹
  • 给 Provider 组件设置 store 的属性,这个值就是通过 createStore 构建出来的 store 实例对象
function App() {
  return (
    <Provider store={ store }>
      <div className="App">
        <CountButton />
        <CountNum />
      </div>
    </Provider>
  );
}

2.7 connect 使用

  • 导入 connect 方法
import { conenct } from 'react-redux'
  • 调用 connect 方法
connect(...)(Component)

connect 参数说明

参数名类型说明
mapStateToProps(state, ownProps)Function1. 这个函数允许我们将 store 中的数据作为props绑定到组件上;2.state: redux 中的 store; 3.ownProps: 自己的props;
mapDispatchToProps(dispatch, ownProps)Function1.将 action 作为 props 绑定到我们自己的函数中;2.dispatch: 就是 store.dispatch()3.ownProps: 自己的props;3. 必须有返回值,为Object 类型
mergeProps(stateProps, dispatchProps, ownProps)Function不管是 stateProps 还是 dispatchProps, 都需要和 ownProps merge之后才会被赋给我们的组件,通常情况下,可以不传这个参数,connect 就会使用 Object.assign 替代改方法
optionsFunction可以定制 connector 的行为
  • 利用 connect 方法让我们组件与 store 关联

    • 在组件 CountButton 和 CountNum 中分别导入 connect 方法
    • 利用 connect 方法来对我们的组件进行加强,并且导出
    • 组件 CountButton 属于发送方,所以要实现第二个参数
    • 组件 CountNum 属于接收方,所以要实现第一个参数

2.8 组件实现

2.8.1 CountButton 发送 action

  • 导入 connect
  • 利用 connect 对组件进行加强:connect(要接受数组的函数,要发送action的函数)(放入要加强的组件)
  • 需要实现第二个参数
    构建函数 mapDispatchToProps(dispatch) ; dispatch就是用来发送 action的
  • 在组件的内部就可以通过 props 来调用这个方法
// CountButton.jsx
import React from 'react'
import { connect } from 'react-redux'
import { addAction, reduceAction } from '../react-redux/actions'

function CountButton(props) {
  const addTen = ()=> {
    props.sendAdd(10)
  }
  const reduceTwo =()=> {
    props.sendReduce(2)
  }
  return (
    <>
      <button onClick={addTen}> +10</button>
      <button onClick={reduceTwo}> -2 </button>
    </>
  )
}
const mapDispatchToProps = dispatch=> {
  return {
    // dispatch 一个 addAction
    sendAdd: (num)=> {
      dispatch(addAction(num))
    },
     // dispatch 一个 reduceAction
    sendReduce: (num)=> {
      dispatch(reduceAction(num))
    }
  }
}

export default connect(null, mapDispatchToProps)(CountButton)

2.8.2 CountNum 接收 state

  • 导入 connect 方法
  • 利用 connect 对组件进行加强
  • CountNum 属于接收方,就需要实现 connect 的第一个参数

mapStateToProps 里面的参数就是我们关心的state,把这个 state 进行return 才能再组件的内部获取到最新的数据;
CountNum 是否能拿到数据的关键在于 reducer , 只有 reducer 里面返回了新的 state 时才能被获取到

import React from 'react'
import { connect } from 'react-redux'
function CountNum(props) {
  return (
    <div>{props.count}</div>
  )
}
const mapStateToProps = state => {
  return state
}
export default connect(mapStateToProps)(CountNum)

3.效果图:

4.源文件

目录结构:

1.创建 reducer/index.js 文件,构建 reducer 来响应actions

// reducer/index.js
const initState={
    count:0
};

/**
    纯函数,接收两个参数
 */
export default function reducer(preState=initState,action){
    console.log('3333333333333333reducer');
    console.log('reducer preState',preState);
    console.log('reducer action',action);
    const { type,payload } = action;
    console.log('reducer type',type);
    console.log('reducer payload',payload);
    switch (type) {
        case 'ADD_NUM':
            return {
                ...preState,
                count:preState.count+payload.num
            };
    
        case 'REDUCE_NUM':
            return {
                ...preState,
                count:preState.count-payload.num
            };
    
        default:
            return preState;;
    }
}

2.创建 store/index.js 文件,通过createStore方法,把我们的reducer传入进来

// store/index.js
import {createStore} from 'redux'
import reducer from '../reducer'

export default createStore(reducer);

3.在app.js中引入 store

import logo from './logo.svg';
import './App.css';
import CountButton from './componments/CountButton'
import CountNum from './componments/CountNum'
import store from './store'
import { Provider } from 'react-redux'
function App() {
  return (
    <div className="App">
      <Provider store={store}>
          <CountButton />
          <CountNum />
        </Provider>
    </div>
  );
}

export default App;

4. 构建页面

  • 实现一个可以处理加减的计数器,页面如下图所示

 

  • 创建一个组件,名字叫CountButton,里面放两个 button 按钮  
    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    import { addAction,reduceAction } from '../action'
    
    class CountButton extends Component {
        addTen=()=>{
            console.log('111111111addTen')
            this.props.sendAdd(10);
        }
        reduceTwo=()=>{
            this.props.reduceAction(2);
        }
    
        render() {
            return (
                <div>
                    <button onClick={()=>this.addTen()}>  +10  </button>
                    <button onClick={()=>this.reduceTwo()} >  -2  </button>
                </div>
            )
        }
    }
    
    
    export default connect(null,{
        sendAdd:addAction,
        reduceAction
    })(CountButton)

  • 创建另外一个组件,名字教 CountNum,里面放一个 div,用来现实数字
    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    
    class CountNum extends Component {
        render() {
            console.log('555555555555555this.props.count',this.props.count);
            return (
                <div>
                    值是:{this.props.count}
                </div>
            )
        }
    }
    
    
    export default connect(
        state=>{  console.log('444444444444444444CountNum connect state',state);   return({count:state.count})}
    )(CountNum)
    

    my-app\src\action\index.js  

    export const addAction=(num)=>{
        console.log('222222222222addAction');
        return {
            type:'ADD_NUM',
            payload:{
                num
            }
        }
    }
    
    export const reduceAction=(num)=>{
        return {
            type:'REDUCE_NUM',
            payload:{
                num
            }
        }
    }

 package.json:

{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-redux": "^7.2.4",
    "react-scripts": "4.0.3",
    "redux": "^4.1.0",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

代码在:https://gitee.com/hopetomorrow2021/my-app.git

5.参考

具体参考:https://segmentfault.com/a/1190000022717625

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值