七步搞定React Redux

PriceLynn 发布于1月前
0 条问题

React是一款非常优秀的前端框架,但是我们不能说它是尽善尽美的。比如说React在做大型项目时,在处理状态管理的问题时就显得捉襟见肘。因此针对于状态管理的问题就衍生出了很多的技术,比如flux,redux等等。在这篇文章中我们只探讨redux,如果小伙伴们学会了redux,就不用再去学习redux,因为redux是flux的一个升级。当然有的小伙伴会问如果他用的是vue或者是angular可不可以用redux呢,这里明确的说明一下都是可以的,哪怕是原生的js也是可以的。

在这篇文章中我将会分为七个步骤来为小伙伴们介绍React Redux,相信看完这篇文章的你就可以很好的应用React Redux了。

准备工作

1.什么是state?

2.什么是redux为什么选择redux?

3.什么是reducer?

4.什么是store?

5.怎么关联store?

6.什么是action?

7.怎么处理异步代码?

总结

另附

准备工作

在准备工作进行之前默认你了解了React和ES6的相关知识。

首先我们在创建项目时用下面的命令行:

npx create-react-app react-redux-example

如果是在创建好的项目中想要使用,应该在执行下面的命令:

npm install redux react-redux

然后我们需要创建一些文件。

  • 1、在src目录下创建一个container文件夹,在container下面创建一个Articles.js文件。
import React, { useState } from "react"
import Article from "../components/Article/Article"
import AddArticle from "../components/AddArticle/AddArticle"

const Articles = () => {
  const [articles, setArticles] = useState([
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ])
  const saveArticle = e => {
    e.preventDefault()
    // 逻辑代码稍后更新
  }

  return (
    <div>
      <AddArticle saveArticle={saveArticle} />
      {articles.map(article => (
        <Article key={article.id} article={article} />
      ))}
    </div>
  )
}

export default Articles
  • 2、在src目录下面创建一个components文件夹,然后创建AddArticle/AddArticle.js和Article/Article.js

Article.js

import React from "react"
import "./Article.css"

const article = ({ article }) => (
  <div className="article">
    <h1>{article.title}</h1>
    <p>{article.body}</p>
  </div>
)

export default article

AddArticle.js

import React, { useState } from "react"
import "./AddArticle.css"

const AddArticle = ({ saveArticle }) => {
  const [article, setArticle] = useState()

  const handleArticleData = e => {
    setArticle({
      ...article,
      [e.target.id]: e.target.value,
    })
  }
  const addNewArticle = e => {
    e.preventDefault()
    saveArticle(article)
  }

  return (
    <form onSubmit={addNewArticle} className="add-article">
      <input
        type="text"
        id="title"
        placeholder="Title"
        onChange={handleArticleData}
      />
      <input
        type="text"
        id="body"
        placeholder="Body"
        onChange={handleArticleData}
      />
      <button>Add article</button>
    </form>
  )
}
export default AddArticle

App.js

import React from "react"
import Articles from "./containers/Articles"

function App() {
  return <Articles />
}
export default App

如果小伙伴们完成了上面的步骤,就可以接着往下进行啦!

1.什么是State?

每一个react 组件(无状态组件除外)的核心都是state。它决定了组建的渲染方式和表现的形式。想要真正的理解state,必须通过实际的例子。比如说弹窗是否打开,组件是否渲染等等。

// Class based component
state = {
  articles: [
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ],
}
// React hooks
const [articles, setArticles] = useState([
  { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
  { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
])

相信小伙伴们现在知道什么是state了,现在就为你们介绍redux。

2.什么是redux为什么使用redux?

如果没有redux或者是其他的工具管理state将变的无比艰难。想象一下我们必须检查每一个组件来看看弹窗是否开启了。为了解决这个问题,我们必须在组件间传递props,这会使组件的数据变得非常的混乱,开发成本也变得很高。但是有了redux一切就变得很简单了。

七步搞定React Redux

3.什么是reducer?

reducer是一个纯函数,它接收之前的state和action作为参数,返回一个更新了的state。reducer只能处理同步的代码,意味着没有像HTTP请求那样的副作用。当然我们也可以用redux来处理异步代码,我们在后续会学习怎样处理。当然如果你对action还不了解那么没有关系,后面会为大家介绍的。下面让我们来创建我们的第一个reducer吧。

按照惯例,我们要创建一个store文件夹,然后创建一个reducer.js文件。

reducer.js文件

const initialState = {
  articles: [
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ],
}

const reducer = (state = initialState, action) => {
  return state
}
export default reducer

reducer就是一个接收了以前的state和action作为参数的纯函数,返回了一个更新后的state。现在我们已经创建好了reducer了,接下来让我们来创建store吧。

4.什么是store?

store是react项目中存储state的地方,你可以把它看成是一个大的JavaScript对象。创建store时我们需要一个reducer来作为参数,我们已经创建好reducer了,让我们把它关联到store上面吧。

import React from "react"
import ReactDOM from "react-dom"
import { createStore } from "redux"

import "./index.css"
import App from "./App"
import reducer from "./store/reducer"

const store = createStore(reducer)

ReactDOM.render(<App />, document.getElementById("root"))

5.怎么把store关联到React?

想把store关联到React,我们需要引入一个辅助函数叫做Provider。然后用Provider组件包裹着App组件,再把store作为props值传入Provider。

index.js文件

import React from "react"
import ReactDOM from "react-dom"
import { createStore } from "redux"
import { Provider } from "react-redux"

import "./index.css"
import App from "./App"
import reducer from "./store/reducer"

const store = createStore(reducer)

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

Articles.js文件

import React from "react"
import { connect } from "react-redux"

import Article from "../components/Article/Article"
import AddArticle from "../components/AddArticle/AddArticle"

const Articles = ({ articles }) => {
  const saveArticle = e => {
    e.preventDefault()
    // ...
  }
  return (
    <div>
      <AddArticle saveArticle={saveArticle} />
      {articles.map(article => (
        <Article key={article.id} article={article} />
      ))}
    </div>
  )
}

const mapStateToProps = state => {
  return {
    articles: state.articles,
  }
}

export default connect(mapStateToProps)(Articles)

在这里我们引入了connect(),它能帮助我们把组件和store连接起来,并且可以获取state。

我们声明了一个新的函数叫 mapStateToProps() ,当然函数名也可以是别的,它从store中获取state值作为它的参数,返回了一个对象。

为了获取到store中的state,我们需要把 mapStateToProps() 作为connect函数的参数。

6.什么是action?

action包含着各种类型,比如REMOVE_ARTICLE 或者 ADD _ ARTICLE等。它从react组件中被分发(传递数据)到redux 的 store 中。当让action只是一个传递信息的,他不能改变store。store只能被reducer改变。

在项目中创建action,我们在store文件夹中先创建一个actionTypes.js

export const ADD_ARTICLE = "ADD_ARTICLE"

然后我们去Articles.js文件

import React from "react"
import { connect } from "react-redux"

import Article from "../components/Article/Article"
import AddArticle from "../components/AddArticle/AddArticle"
import * as actionTypes from "../store/actionTypes"

const Articles = ({ articles, saveArticle }) => (
  <div>
    <AddArticle saveArticle={saveArticle} />
    {articles.map(article => (
      <Article key={article.id} article={article} />
    ))}
  </div>
)

const mapStateToProps = state => {
  return {
    articles: state.articles,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    saveArticle: article =>
      dispatch({ type: actionTypes.ADD_ARTICLE, articleData: { article } }),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Articles)

在这里我们从actionTypes.js中引入了 everything 。然后创建了一个新的函数mapDispatchToProps ,它接收dispatch作为参数。

store/reducer.js文件

import * as actionTypes from "./actionTypes"

const initialState = {
  articles: [
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ],
}

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case actionTypes.ADD_ARTICLE:
      const newArticle = {
        id: Math.random(), // not really unique but it's just an example
        title: action.article.title,
        body: action.article.body,
      }
      return {
        ...state,
        articles: state.articles.concat(newArticle),
      }
  }
  return state
}
export default reducer

我们引入了actionTypes。然后我们检查reducer函数看看action的类型是否是 ADD_ARTICLE。如果是的话我们创建了一个对象,返回了一个新的state。

7.redux怎么处理异步代码?

我们需要创建一个新的文件 actionCreators.js

store/actionCreators.js

import * as actionTypes from "./actionTypes"

export const addArticle = article => {
  return {
    type: actionTypes.ADD_ARTICLE,
    article,
  }
}

Articles.js

import React from "react"
import { connect } from "react-redux"

import Article from "../components/Article/Article"
import AddArticle from "../components/AddArticle/AddArticle"
import { addArticle } from "../store/actionCreators"

const Articles = ({ articles, saveArticle }) => (
  <div>
    <AddArticle saveArticle={saveArticle} />
    {articles.map(article => (
      <Article key={article.id} article={article} />
    ))}
  </div>
)

const mapStateToProps = state => {
  return {
    articles: state.articles,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    saveArticle: article => dispatch(addArticle(article)),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Articles)

现在还没有完成袄,我们还需引入一个新的依赖包redux-thunk,redux-thunk 是一个中间件它可以使我们处理异步代码。

npm install redux-thunk

index.js文件

import React from "react"
import ReactDOM from "react-dom"
import { createStore, applyMiddleware } from "redux"
import { Provider } from "react-redux"
import thunk from "redux-thunk"

import "./index.css"
import App from "./App"
import reducer from "./store/reducer"

const store = createStore(reducer, applyMiddleware(thunk))

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

store/actionCreators.js

import * as actionTypes from "./actionTypes"

export const addArticle = article => {
  return {
    type: actionTypes.ADD_ARTICLE,
    article,
  }
}

export const simulateHttpRequest = article => {
  return dispatch => {
    setTimeout(() => {
      dispatch(addArticle(article))
    }, 3000)
  }
}

Articles.js

import React from "react"
import { connect } from "react-redux"

import Article from "../components/Article/Article"
import AddArticle from "../components/AddArticle/AddArticle"
import { simulateHttpRequest } from "../store/actionCreators"

const Articles = ({ articles, saveArticle }) => (
  <div>
    <AddArticle saveArticle={saveArticle} />
    {articles.map(article => (
      <Article key={article.id} article={article} />
    ))}
  </div>
)

const mapStateToProps = state => {
  return {
    articles: state.articles,
  }
}

const mapDispatchToProps = dispatch => {
  return {
    saveArticle: article => dispatch(simulateHttpRequest(article)),
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Articles)

在这里我们做的唯一的改变就是把addArticle 变成了 simulateHttpRequest,现在我们就可以通过redux来执行异步代码了。

总结

当我们在处理中大型的react项目是,管理我们的state就变得非常的困难。有了redux就变得非常简单了,当然了还有很多其他的解决办法像 context API(hook)在处理state管理的问题时也是非常好用的。

最后,大家可以关注我的文章,定期为小伙伴们分享前端的知识,希望能够帮助到小伙伴们。

另附

本文参考了Redux官网,还有网上一些好文章,如有侵权,请联系我,谢谢。

查看原文: 七步搞定React Redux

  • crazylion
  • blackgorilla
  • ticklishostrich
  • greengoose
  • crazybutterfly
  • crazygoose
  • purpledog
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。