前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用Redux和React-redux在React中进行状态管理

使用Redux和React-redux在React中进行状态管理

作者头像
前端修罗场
发布2022-07-29 07:59:25
2.9K0
发布2022-07-29 07:59:25
举报
文章被收录于专栏:Web 技术

首先,我们需要使用create-react-app命令行工具安装新的react应用。

运行以下命令安装react app

代码语言:javascript
复制
npx create-react-app redux-tutorial

上面的命令将把与React相关的文件下载到“ redux-tutorial”文件夹中。

一旦成功安装,请使用以下命令将工作目录更改为应用程序目录。

代码语言:javascript
复制
cd redux-tutorial
npm start

npm start命令用于打开本地开发服务器localhost:3000

安装Redux库

让我们使用以下命令安装reduxandreact-redux库。

代码语言:javascript
复制
npm i redux react-redux

redux:Redux用于管理状态

react-redux:用于在react和redux库之间进行绑定。

现在,使用您喜欢的代码编辑器打开“ redux-tutorial”文件夹。

Reducer

Reducer函数是一个纯函数,它采用上一个应用程序状态,type of action并返回下一个状态而不会改变前一个状态。

Redux遵循不变性,这意味着我们不改变应用程序状态,而不是返回 新的应用程序状态。

Redux在单个JavaScript对象中管理整个应用程序状态。

reducerssrc目录中创建一个新文件夹。

在reducers内,文件夹创建一个名为的新文件reducer.js。

代码语言:javascript
复制
// reducer.js
const intialState = { name: "reactgo", allNames: []}

const reducer = (state = intialState, action) => {

    if (action.type === "ADDNAME") {
        return {
            allNames: state.allNames.concat(state.name),
            name: ""
        }
    }

    if (action.type === "CHANGE_NAME") {
        return {
            ...state,
            name: action.name
        }
    }

    return state
}

export default reducer;

在上面的代码中,我们定义了带有两个参数state和的reducer函数action。在reducer函数内部,我们添加了两个条件语句。我们的初始状态对象是 { name: "", allNames: []}

将React与Redux连接

代码语言:javascript
复制
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux'
import { Provider } from 'react-redux';
import App from './App';
import reducer from './reducers/reducer'

const store = createStore(reducer);

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>
    , document.getElementById('root'));

index.js文件内部,我们从“ redux”库中导入了createStore函数,并从react-redux库中导入 Provider 组件。

我们通过将函数作为参数传递来调用createStore函数,并通过传递store属性reducer<Provider>组件与<App/>组件包装 在一起。

<Provider> 组件使用react context API通过组件树向下传递状态。

从组件访问Redux状态

现在我们可以直接从React组件访问我们的redux状态。

打开App.js文件并添加以下代码。

mapStatetoProps示例

代码语言:javascript
复制
import React, { Component } from 'react';
import { connect } from 'react-redux'
import './App.css'

class App extends Component {

  render() {
    return (
      <div className="App">

        <div>
          <input type="text"
            placeholder="Name"
            value={this.props.name} />
      </div>
    );
  }
}


const mapStatetoProps = (state) => {
  return {
    name: state.name,
  }
}

export default connect(mapStatetoProps)(App);

在这里,我们首先导入connectreact-redux库中调用的高阶组件,然后使用state参数定义一个函数mapStatetoProps。

通过使用状态参数, 我们可以访问在reducer函数内部定义的redux状态。

我们mapStatetoProps函数内部定义的任何属性都可以用作App组件内部的props ,例如,在上面的组件中,我们返回的对象带有{name:state.name},这样我们就可以以这样的形式访问组件name内部的该属性。Appthis.props.name

最后,我们需要connect,通过将mapStatetoProps参数作为参数来调用该函数。

如果现在打开浏览器,您会看到“ reactgo”显示在该input字段内。

改变Redux状态

redux状态树是只读的,我们不能直接改变状态。

在redux中,我们只能通过调用dispatch类型为的方法来改变状态action

如果你打开reducer.js文件,你可以看到他们有两种类型,其可用的action为ADDNAMECHANGE_NAME

代码语言:javascript
复制
reducer.js
const intialState = { name: "reactgo", allNames: []}

const reducer = (state = intialState, action) => {

    if (action.type === "ADDNAME") {
        return {
            allNames: state.allNames.concat(state.name),
            name: ""
        }
    }

    if (action.type === "CHANGE_NAME") {
        return {
            ...state,
            name: action.name
        }
    }

    return state
}

export default reducer;

如果我们使用类型调用方法ADDNAME,那么我们将返回新状态,并将 name属性值添加到allNames数组中并重置name属性。

让我们看看实际情况。

打开App.js文件,添加以下代码。

mapDispatchtoProps示例

代码语言:javascript
复制
// App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import './App.css'

class App extends Component {


  handleNameChange = (e) => {
    this.props.onChangeName(e.target.value)
  }


  render() {
    return (
      <div className="App">

        <div>
          <input type="text"
            placeholder="Name"
            value={this.props.name} onChange={this.handleNameChange} />

          <button onClick={this.props.onAddName}>Add name</button>

          <ul>
            {this.props.allNames && this.props.allNames.map(name => (
              <li key={name}> {name}</li>
            ))}
          </ul></div>

      </div>
    );
  }
}


const mapStatetoProps = (state) => {
  return {
    name: state.name,
    allNames: state.allNames
  }
}


const mapDispatchtoProps = (dispatch) => {
  return {
    onChangeName: (name) => dispatch({ type: "CHANGE_NAME", name: name }),
    onAddName: () => dispatch({ type: "ADDNAME" }),
  }
}

export default connect(mapStatetoProps, mapDispatchtoProps)(App);

在上面,我们定义了一个mapDispatchtoProps函数,将dispatch方法作为函数参数。

mapDispatchtoProps函数内部,我们返回了一个具有两个属性的对象onChangeNameonAddName

onChangeName:它可以帮助我们了解用户添加dispatch的操作类型CHANGE_NAME和有效负载name属性。

onAddName:它有助于我们dispatch采取行动类型ADDNAME

我们可以App作为来访问组件内部的这两个属性props

现在让我们在浏览器中对其进行测试。

错误处理

我们还可以通过ERROR在reducer函数中创建一个类型来处理错误。

reducer.js使用以下代码更新文件:

代码语言:javascript
复制
// reducer.js
const intialState = { name: "reactgo", allNames: [], error: "" }

const reducer = (state = intialState, action) => {

    if (action.type === "ADDNAME") {
        return {
            allNames: state.allNames.concat(state.name),
            name: ""
        }
    }

    if (action.type === "CHANGE_NAME") {
        return {
            ...state,
            name: action.name
        }
    }

    if (action.type === "ERROR") {
        return {
            ...state,
            error: action.error
        }
    }

    return state
}
export default reducer;

在上面的代码中,我们reducer通过添加第三个条件语句来更新我们的函数,该条件语句的类型ERRORerror属性被添加到我们的initialState对象中。

让我们ERRORApp组件中dispatch action类型。

代码语言:javascript
复制
// App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import './App.css'

class App extends Component {


  handleNameChange = (e) => {
    this.props.onChangeName(e.target.value)
  }

  handleClick = () => {

    if (this.props.name) {
      this.props.onAddName()
    } else {
      this.props.onError("Name field cannot be empty")
    }

  }

  render() {
    return (
      <div className="App">

        <div>
          <input type="text"
            placeholder="Name"
            value={this.props.name} onChange={this.handleNameChange} />
          <button onClick={this.handleClick}>Add name</button>

          <p className={this.props.error ? "error active" : "error"}>
          {this.props.error}</p>
          <ul>
            {this.props.allNames && this.props.allNames.map(name => (
              <li key={name}> {name}</li>
            ))}
          </ul></div>

      </div>
    );
  }
}


const mapStatetoProps = (state) => {
  return {
    name: state.name,
    error: state.error,
    allNames: state.allNames
  }
}


const mapDispatchtoProps = (dispatch) => {
  return {
    onChangeName: (name) => dispatch({ type: "CHANGE_NAME", name: name }),
    onAddName: () => dispatch({ type: "ADDNAME" }),
    onError: (err) => dispatch({ type: "ERROR", error: err })
  }
}

export default connect(mapStatetoProps, mapDispatchtoProps)(App);

在上面的代码中,我们在handleClick方法内部添加了条件检查,以便每当用户尝试单击Add name按钮而不输入名称时,我们都会 通过传递错误消息来调用this.props.onError方法。

重构代码

很难在许多地方手动键入操作类型,因此我们要创建两个新文件,分别是actionCreators.jsactionTypes.js

actionTypes.js文件中,我们正在定义所有动作类型。

目前,我们的应用程序中包含三种类型的操作CHANGE_NAMEADDNAME以及ERROR

actionssrc目录中创建一个文件夹。

actions文件夹内创建一个actionTypes.js文件和以下代码。

代码语言:javascript
复制
// actionTypes.js
export const ADDNAME = "ADDNAME";
export const CHANGE_NAME = "CHANGE_NAME";
export const ERROR = "ERROR";

actionCreators.jsactions文件夹中创建一个新文件。

代码语言:javascript
复制
// actionCreators.js
import { CHANGE_NAME, ADDNAME, ERROR } from './actionTypes'


export function changeName(name) {
    return {
        type: CHANGE_NAME,
        name: name
    }
}

export function addname() {
    return {
        type: ADDNAME
    }
}
export function error(msg) {
    return {
        type: ERROR,
        error: msg
    }
}

在上面,我们创建了三个action创建器,它们返回三种不同类型的动作。

Action创建者是JavaScript函数,它们以一种action类型返回对象。

使用更新您的reducer.js文件actionTypes

代码语言:javascript
复制
// reducer.js
import { CHANGE_NAME, ADDNAME, ERROR } from '../actions/actionTypes'

const intialState = { name: "reactgo", allNames: [], error: "" }

const reducer = (state = intialState, action) => {

    if (action.type === ADDNAME) {
        return {
            allNames: state.allNames.concat(state.name),
            name: ""
        }
    }

    if (action.type === CHANGE_NAME) {
        return {
            ...state,
            name: action.name
        }
    }

    if (action.type === ERROR) {
        return {
            ...state,
            error: action.error
        }
    }

    return state


}
export default reducer;

App.js使用actionCreate()更新文件。

代码语言:javascript
复制
// App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { addname, error, changeName } from './actions/actionCreators'
import './App.css'

class App extends Component {


  handleNameChange = (e) => {
    this.props.onChangeName(e.target.value)
  }

  handleClick = () => {

    if (this.props.name) {
      this.props.onAddName()
    } else {
      this.props.onError("Name field cannot be empty")
    }

  }

  render() {
    return (
      <div className="App">

        <div>
          <input type="text"
            placeholder="Name"
            value={this.props.name} onChange={this.handleNameChange} />
          <button onClick={this.handleClick}>Add name</button>
          <p className={this.props.error ? "error active" : "error"}>
          {this.props.error}</p>
          <ul>
            {this.props.allNames && this.props.allNames.map(name => (
              <li key={name}> {name}</li>
            ))}
          </ul></div>

      </div>
    );
  }
}


const mapStatetoProps = (state) => {
  return {
    name: state.name,
    error: state.error,
    allNames: state.allNames
  }
}


const mapDispatchtoProps = (dispatch) => {
  return {
    onChangeName: (name) => dispatch(changeName(name)),
    onAddName: () => dispatch(addname()),
    onError: (err) => dispatch(error(err))
  }
}

export default connect(mapStatetoProps, mapDispatchtoProps)(App);
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端修罗场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装Redux库
    • 改变Redux状态
      • 错误处理
        • 重构代码
        相关产品与服务
        命令行工具
        腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档