react之redux教程:全网讲解redux最清晰文章

redux

redux 基本介绍

概念

redux是一个用来管理状态(数据)的框架。

为什么要用redux?

例如,一个组建的数据共享到其他组建,A1-1组建的数据要在A2和A2-1中使用,用以往的方式通过组建间传递也能实现,但是太过麻烦,如果项目较大,数据交互较多的场景,数据维护更为复杂,所以更适合将公共的数据放到公共的仓库中。

在这里插入图片描述
事实上,大多数情况,你可以不用它,只用 React 就够了。

曾经有人说过这样一句话。

“如果你不知道是否需要 Redux,那就是不需要它。”

Redux 的创造者 Dan Abramov 又补充了一句。

“只有遇到 React 实在解决不了的问题,你才需要 Redux 。”

简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。

  • 用户的使用方式非常简单
  • 用户之间没有协作
  • 不需要与服务器大量交互,也没有使用 WebSocket
  • 视图层(View)只从单一来源获取数据

上面这些情况,都不需要使用 Redux。

我不做大型项目,那么我还要去学习吗?

当然要学,现在不做大型项目,不代表以后不做大型项目,要为未来铺路,面试关于react技术栈,几乎必问redux,所以也为面试增砖添瓦。

准备工作

  • 利用create-react-app快速初始化项目

    create-react-app redux-demo
    
  • 清理项目结构

  • 安装redux

    npm i redux
    

redux快速上手

创建stroe仓库

  • 在src下创建store文件夹,在store下创建index.js

  • 创建redux仓库

    import { createStore } from 'redux'
    const defaultState = {
      count: 1
    }
    const store =  createStore((state = defaultState) => {
      return state
    })
    
    export default store
    

getState

  • 通过getState获取仓库的数据并展示

    import React from 'react';
    import store from './store'
    export default class App extends React.Component {
    
      constructor (props) {
        super(props)
        this.state = store.getState()
      }
    
      render () {
        return (
          <div>
            { this.state.count }
          </div>
        )
      }
    
    }
    

定义reducer

  • 创建reducer.js文件

    // 仓库数据
    const defaultState = {
      count: 1
    }
    const reducer = (state = defaultState) => {
      return state
    }
    
    export default reducer
    
  • 在store/index.js中引入

    import { createStore } from 'redux'
    import reducer from './reducer'
    const store =  createStore(reducer)
    
    export default store
    

计数器案例

准备工作

  • 准备Add组建

    import React from 'react';
    import store from './store'
    export default class Add extends React.Component {
    
      constructor (props) {
        super(props)
        this.state = store.getState()
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button>+1</button>
          </div>
        )
      }
    
    }
    
  • 准备sub组建

    import React from 'react';
    import store from './store'
    export default class Sub extends React.Component {
    
      constructor (props) {
        super(props)
        this.state = store.getState()
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button>-1</button>
          </div>
        )
      }
    
    }
    
  • 在App中使用

    import React from 'react';
    import Add from './Add'
    import Sub from './Sub'
    export default class App extends React.Component {
    
      render () {
        return (
          <div>
            <Add />
            <p>-----------</p>
            <Sub />
          </div>
        )
      }
    
    }
    

实现累加

错误🙅‍♂️写法
  • 这样只修改了当前组建state,并不是修改了redux的store仓库的数据

    addCount = () => {
        this.setState({
          count: this.state.count + 1
        })
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button onClick={ this.addCount }>+1</button>
          </div>
        )
      }
    
正确🙆‍♂️写法
  • add组建注册点击事件

    render () {
      return (
        <div>
          { this.state.count }
          <button onClick={ this.addCount }>+1</button>
        </div>
      )
    }
    
  • 通过dispatch触发修改state的操作,进行数据修改,参数是action

    addCount = () => {
      store.dispatch({
        type: 'addCount'
      })
    }
    
  • 在reducer纯函数中的第二个参数为action,action可以获取到dispatch操作的类型和数据

    const reducer = (state = defaultState, action) => {
      // reducer 不允许直接修改 state的数据
      if (action.type === 'addCount') {
        const newState = {
          ...state,
          count: state.count + 1
        }
        return newState
      }
      return state
    }
    
安装redux-devtools
  • 极简插件下载安装

  • 配置

    const store = createStore(
       reducer, /* preloadedState, */
    +  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
     );
    
实现数据更新
  • 通过store.subscribe的回调监听数据发生变化

    componentDidMount () {
      store.subscribe(this.storeChange)
    }
    
    storeChange = () => {
      this.setState({
        ...store.getState()
      })
    }
    
  • 给sub组建同样添加

传递数据
  • 传递数据

    addCount = () => {
        store.dispatch({
          type: 'addCount',
          value: 2
        })
      }
    
  • 接收数据

    // 仓库数据
    const defaultState = {
      count: 1
    }
    const reducer = (state = defaultState, action) => {
      // reducer 不允许直接修改 state的数据
      if (action.type === 'addCount') {
        const newState = {
          ...state,
          count: state.count + action.value
        }
        return newState
      }
      return state
    }
    
    export default reducer
    

实现累减

  • 注册事件

    subCount = () => {
        store.dispatch({
          type: 'subCount',
          value: 2
        })
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button onClick={this.subCount}>-1</button>
          </div>
        )
      }
    
  • reducer中通过action处理

    const reducer = (state = defaultState, action) => {
      // reducer 不允许直接修改 state的数据
      if (action.type === 'addCount') {
        const newState = {
          ...state,
          count: state.count + action.value
        }
        return newState
      }
    
      if (action.type === 'subCount') {
        const newState = {
          ...state,
          count: state.count - action.value
        }
        return newState
      }
      return state
    }
    

redux工作流程

  • 定义store数据仓库
  • 通过store.getState()获取仓库数据
  • 当组建视图发生更新通过dispatch创建action触发修改state的操作
  • 在reducer中通过action获取修改操作和数据对store数据进行更新
  • 组建内部通过通过store.subscribe的回调监听数据发生变化从而重新更新试图

在这里插入图片描述

优化action处理

因为在修改数据的时候,要通过store.dispath创建的type类型的值,和action中约定的值,从而实现数据修改,但是如果store.dispath创建的type类型的值或者action中约定的值写错,此时并不会报错,功能也不会实现,进而对调试有了难度。

  • 创建actionType

    const ADD_COUNT = 'ADD_COUNT'
    const SUB_COUNT = 'SUB_COUNT'
    
    export {
      ADD_COUNT,
      SUB_COUNT
    }
    
  • 修改reducer.js

    import { ADD_COUNT, SUB_COUNT } from './actionType'
    // 仓库数据
    const defaultState = {
      count: 1
    }
    const reducer = (state = defaultState, action) => {
      // reducer 不允许直接修改 state的数据
      if (action.type === ADD_COUNT) {
        const newState = {
          ...state,
          count: state.count + action.value
        }
        return newState
      }
    
      if (action.type === SUB_COUNT) {
        const newState = {
          ...state,
          count: state.count - action.value
        }
        return newState
      }
      return state
    }
    
    export default reducer
    
  • 修改Add组建

    import React from 'react';
    import store from './store'
    import { ADD_COUNT } from './store/actionType'
    export default class Add extends React.Component {
    
      constructor (props) {
        super(props)
        this.state = store.getState()
      }
    
      componentDidMount () {
        store.subscribe(this.storeChange)
      }
    
      storeChange = (e) => {
        console.log(123)
        this.setState({
          ...store.getState()
        })
      }
    
      addCount = () => {
        store.dispatch({
          type: ADD_COUNT,
          value: 2
        })
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button onClick={ this.addCount }>+1</button>
          </div>
        )
      }
    
    }
    
  • 修改Sub组建

    import React from 'react';
    import store from './store'
    import { SUB_COUNT } from './store/actionType'
    export default class Sub extends React.Component {
    
      constructor (props) {
        super(props)
        this.state = store.getState()
      }
    
      componentDidMount () {
        store.subscribe(this.storeChange)
      }
      
      storeChange = () => {
        this.setState({
          ...store.getState()
        })
      }
    
      subCount = () => {
        store.dispatch({
          type: SUB_COUNT,
          value: 2
        })
      }
    
      render () {
        return (
          <div>
            { this.state.count }
            <button onClick={this.subCount}>-1</button>
          </div>
        )
      }
    
    }
    

异步获取数据

通过axios获取数据

  • 安装axios

    yarn add axios
    
  • 在Add组建中引入axios获取数据

    import axios from 'axios'
    
    componentDidMount () {
        store.subscribe(this.storeChange)
        this.loadNewsList()
      }
    
      async loadNewsList () {
        const { data: res } = await axios.get('http://115.159.87.220:4000/books')
        console.log(res)
      }
    

将数据保存到store

  • 定义type类型

    const ADD_COUNT = 'ADD_COUNT'
    const SUB_COUNT = 'SUB_COUNT'
    const GET_NEWS = 'GET_NEWS'
    
    export {
      ADD_COUNT,
      SUB_COUNT,
      GET_NEWS
    }
    
  • 引入GET_NEWS并通过dispatch触发action

    import { ADD_COUNT, GET_NEWS } from './store/actionType'
    async loadNewsList () {
        const { data: res } = await axios.get('http://115.159.87.220:4000/books')
        console.log(res)
        store.dispatch({
          type: GET_NEWS,
          value: res
        })
      }
    
  • 在reducer中修改数据

    import { ADD_COUNT, SUB_COUNT, GET_NEWS } from './actionType'
    // 仓库数据
    const defaultState = {
      count: 1,
      news: []
    }
    const reducer = (state = defaultState, action) => {
      // reducer 不允许直接修改 state的数据
      if (action.type === ADD_COUNT) {
        const newState = {
          ...state,
          count: state.count + action.value
        }
        return newState
      }
    
      if (action.type === SUB_COUNT) {
        const newState = {
          ...state,
          count: state.count - action.value
        }
        return newState
      }
    
      if (action.type === GET_NEWS) {
        const newState = {
          ...state,
          news: action.value
        }
        return newState
      }
      return state
    }
    
    export default reducer
    
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Redux Toolkit和React Redux库来创建React应用程序中的Redux状态管理。官方推荐的方式是使用官方的Redux JS模板或Redux TS模板,它们基于Create React App并集成了Redux Toolkit和React Redux。 对于使用纯JavaScriptRedux模板,可以使用以下命令创建新的React应用程序: ``` npx create-react-app my-app --template redux ``` 对于使用TypeScript的Redux模板,可以使用以下命令创建新的React应用程序: ``` npx create-react-app my-app --template redux-typescript ``` 在Redux中,首先需要创建一个存储状态的store。整个项目只能有一个store,可以在index.js(或其他入口文件)中创建它。使用Redux的createStore函数来创建store,并将其作为属性传递给Provider组件,如下所示: ```javascript import React from 'react'; import ReactDOM from 'react-dom'; import './index.scss'; import ToDoList from './containers/ToDoList'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import reducer from './reducers/common'; const store = createStore(reducer); ReactDOM.render( <Provider store={store}> <ToDoList /> </Provider>, document.getElementById('root') ); ``` 这样,Redux的store就被创建并与React应用程序连接起来了。你可以在ToDoList组件或其他组件中使用Redux的connect函数来连接store并访问其中的状态和操作。 希望这个回答对你有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [React-redux使用教程](https://blog.csdn.net/xm1037782843/article/details/127606426)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [React学习(三):Redux入门教程](https://blog.csdn.net/sinat_33523805/article/details/102718979)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值