30天入坑React ---------------day20 Live - Updating Redux

这篇文章是30天React系列的一部分 。

在本系列中,我们将从非常基础开始,逐步了解您需要了解的所有内容,以便开始使用React。如果您曾经想学习React,那么这里就是您的最佳选择!

下载免费的PDF

30天的React Mini-Ebook

Redux actions (Redux动作)

在Github上编辑此页面


 在线演示

GitHub:https://github.com/lenvo222/Redux_Actions.git


有了Redux,让我们来谈谈我们如何从应用程序中实际修改Redux状态。

昨天我们经历了将React应用程序与Redux集成的困难部分。从现在开始,我们将使用Redux设置定义功能。

就目前而言,我们的演示应用程序显示了当前时间。但目前没有任何方法可以更新到新的时间。我们现在修改它。

Triggering updates(触发更新)

回想一下,我们在Redux中更改数据的唯一方法是通过动作创建者。我们昨天创建了一个redux商店,但我们还没有为我们创建更新商店的方法。

我们想要的是我们的用户能够通过点击按钮来更新时间。要添加此功能,我们必须采取以下几个步骤:

 

  1. Create an actionCreator to dispatch the action on our store
  2. Call the actionCreator onClick of an element
  3. Handle the action in the reducer

  1. 创建一个actionCreator来在我们的商店上调度操作
  2. 调用onClick元素的actionCreator
  3. 处理减速器中的动作

我们已经实现了第三步,因此我们只需要做两件事就可以使这个功能正常运行。


Yesterday, we discussed what actions are, but not really why we are using this thing called actionCreators or what they are.

昨天,我们讨论了什么是行动,但不是真的为什么我们使用这个名为actionCreators的东西或Action是什么的东西。

As a refresher, an action is a simple object that must include a type value. We created a types.js file that holds on to action type constants, so we can use these values as the type property.

作为复习,动作是一个必须包含type值的简单对象。我们创建了一个types.js保存动作类型常量的文件,因此我们可以使用这些值作为type属性。

export const FETCH_NEW_TIME = 'FETCH_NEW_TIME';

As a quick review, our actions can be any object value that has the type key. We can send data along with our action (conventionally, we'll pass extra data along as the payload of an action).

作为快速回顾,我们的操作可以是具有type Key(密钥)的任何对象值。我们可以将数据与我们的操作一起发送(通常,我们会将额外的数据作为payload操作传递)。

{
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString()
}

Now we need to dispatch this along our store. One way we could do that is by calling the store.dispatch() function.

现在,我们需要派遣沿着我们这store。我们可以做的一种方法是调用store.dispatch()函数。

store.dispatch({
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString()
})

However, this is pretty poor practice. Rather than dispatch the action directly, we'll use a function to return an action... the function will create the action (hence the name: actionCreator). This provides us with a better testing story (easy to test), reusability, documentation, and encapsulation of logic.

然而,这是非常糟糕的做法。我们不是直接调度动作,而是使用函数返回动作......函数将创建动作(因此名称:actionCreator)。这为我们提供了更好的测试故事(易于测试),可重用性,文档和逻辑封装。

Let's create our first actionCreator in a file called redux/actionCreators.js. We'll export a function who's entire responsibility is to return an appropriate action to dispatch on our store.

让我们actionCreator在一个名为的文件中创建第一个redux/actionCreators.js。我们将导出一个函数,他的全部责任是返回适当的操作以在我们的商店发送。

import * as types from './types';

export const fetchNewTime = () => ({
  type: types.FETCH_NEW_TIME,
  payload: new Date().toString(),
})

export const login = (user) => ({
  type: types.LOGIN,
  payload: user
})

export const logout = () => ({
  type: types.LOGOUT,
})

Now if we call this function, nothing will happen except an action object is returned. How do we get this action to dispatch on the store?

现在,如果我们调用此函数,除了返回一个操作对象之外什么都不会发生。我们如何让这个行动在商店发货?

Recall we used the connect() function export from react-redux yesterday? The first argument is called mapStateToProps, which maps the state to a prop object. The connect() function accepts a second argument which allows us to map functions to props as well. It gets called with the dispatch function, so here we can bind the function to call dispatch() on the store.

回想一下,我们昨天使用了connect()函数导出react-redux?调用第一个参数mapStateToProps,将状态映射到prop对象。该connect()函数接受第二个参数,它允许我们将函数映射到props。它被dispatch函数调用,所以在这里我们可以绑定函数来调用dispatch()商店。

Let's see this in action. In our src/views/Home/Home.js file, let's update our call to connect by providing a second function to use the actionCreator we just created. We'll call this function mapDispatchToProps.

让我们看看这个在行动。在我们的src/views/Home/Home.js文件中,让我们通过提供第二个函数来更新我们对connect的调用,以使用我们刚刚创建的actionCreator。我们称之为此功能mapDispatchToProps

import { fetchNewTime } from '../../redux/actionCreators';
  // ...
const mapDispatchToProps = dispatch => ({
  updateTime: () => dispatch(fetchNewTime())
})
  // ...
export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Home);

Home.js  注意下

//...
const mapStateToProps = state => {
    return {
        currentTime: state.time.currentTime
    }
}
const mapDispatchToProps = dispatch => ({
    updateTime: () => dispatch(fetchNewTime())
})
export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(Home);

现在的Home.js代码 

import React from 'react';
import {connect} from 'react-redux';
import {fetchNewTime} from "../../redux/actionCreators";

const Home = (props) => {
    return (
        <div className="home">
            <h1>Welcome home!</h1>
            <p>Current time: {props.currentTime}</p>
        </div>
    );
}


const mapStateToProps = state => {
    return {
        currentTime: state.currentTime
    }
}
const mapDispatchToProps = dispatch => ({
    updateTime: () => dispatch(fetchNewTime())
})
export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(Home);

 

Now the updateTime() function will be passed in as a prop and will call dispatch() when we fire the action. Let's update our <Home /> component so the user can press a button to update the time.

现在该updateTime()函数将作为prop传递,并dispatch()在我们触发动作时调用。让我们更新我们的<Home />组件,以便用户可以按一个按钮来更新时间。

const Home = (props) => {
  return (
    <div className="home">
      <h1>Welcome home!</h1>
      <p>Current time: {props.currentTime}</p>
      <button onClick={props.updateTime}>
        Update time
      </button>
    </div>
  );
}

Although this example isn't that exciting, it does showcase the features of redux pretty well. Imagine if the button makes a fetch to get new tweets or we have a socket driving the update to our redux store. This basic example demonstrates the full functionality of redux. 

虽然这个例子并不那么令人兴奋,但它确实很好地展示了redux的功能。想象一下,如果按钮进行获取以获取新推文,或者我们有一个套接字驱动更新到我们的redux商店。这个基本示例演示了redux的全部功能。


Multi-reducers(多减速器)

As it stands now, we have a single reducer for our application. This works for now as we only have a small amount of simple data and (presumably) only one person working on this app. Just imagine the headache it would be to develop with one gigantic switch statement for every single piece of data in our apps...

就目前而言,我们的应用只有一台减速机。这是现在有效的,因为我们只有少量的简单数据,并且(可能)只有一个人在这个应用程序上工作。想象一下,对于我们的应用程序中的每一条数据,使用一个巨大的开关语句来开发会令人头痛...

Ahhhhhhhhhhhhhh ...

 

Redux to the rescue! Redux has a way for us to split up our redux reducers into multiple reducers, each responsible for only a leaf of the state tree.

Redux来救援!Redux有一种方法让我们将redux减速器分解为多个减速器,每个减速器只负责状态树的一片叶子。

 

We can use the combineReducers() export from redux to compose an object of reducer functions. For every action that gets triggered, each of these functions will be called with the corresponding action. Let's see this in action.

我们可以使用combineReducers()export from redux来组成reducer函数的对象。对于每个被触发的动作,将使用相应的动作调用这些函数中的每一个。让我们看看这个在行动。

 

Let's say that we (perhaps more realistically) want to keep track of the current user. Let's create a currentUser redux module in... you guessed it: src/redux/currentUser.js:

假设我们(可能更现实地)想要跟踪当前用户。让我们创建一个currentUserredux模块......你猜对了src/redux/currentUser.js

touch src/redux/currentUser.js

We'll export the same four values we exported from the currentTime module... of course, this time it is specific to the currentUser. We've added a basic structure here for handling a current user: 

我们将导出从currentTime模块导出的相同四个值...当然,这次是特定于currentUser。我们在这里添加了一个基本结构来处理当前用户:

import * as types from './types'

export const initialState = {
  user: {},
  loggedIn: false
}

export const reducer = (state = initialState, action) => {
  switch (action.type) {
    case types.LOGIN:
      return {
        ...state, user: action.payload, loggedIn: true};
    case types.LOGOUT:
      return {
        ...state, user: {}, loggedIn: false};
    default:
      return state;
  }
}

Let's update our configureStore() function to take these branches into account, using the combineReducers to separate out the two branches 

让我们更新我们的configureStore()函数来考虑这些分支,使用它combineReducers来分离出两个分支

import { createStore, combineReducers } from 'redux';

import { rootReducer, initialState } from './reducers'
import { reducer, initialState as userInitialState } from './currentUser'

export const configureStore = () => {
  const store = createStore(
    combineReducers({
      time: rootReducer,
      user: reducer
    }), // root reducer
    {
      time: initialState, 
      user: userInitialState
    }, // our initialState
  );

  return store;
}

export default configureStore;

Now we can create the login() and logout() action creators to send along the action on our store.

现在我们可以创建login()logout()动作创建者来发送我们商店的动作。

export const login = (user) => ({
  type: types.LOGIN,
  payload: user
})
  // ...
export const logout = () => ({
  type: types.LOGOUT,
})

然后更新Home.js(完整的)代码如下

import React from 'react';
import {connect} from 'react-redux';
import {fetchNewTime} from "../../redux/actionCreators";

const Home = (props) => {
    return (
        <div className="home">
            <h1>Welcome home!</h1>
            <p>Current time: {props.currentTime}</p>
            <button onClick={props.updateTime}>
                Update time
            </button>
        </div>
    );
}


const mapStateToProps = state => {
    return {
        currentTime: state.time.currentTime
    }
}
const mapDispatchToProps = dispatch => ({
    updateTime: () => dispatch(fetchNewTime())
})
export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(Home);

Now we can use the actionCreators to call login and logout just like the updateTime() action creator.

现在我们可以使用actionCreators来调用loginlogout就像updateTime()动作创建者一样。

Phew! This was another hefty day of Redux code. Today, we completed the circle between data updating and storing data in the global Redux state. In addition, we learned how to extend Redux to use multiple reducers and actions as well as multiple connected components.

唷!这是Redux代码的另一个重要日子。今天,我们在全局Redux状态下完成了数据更新和存储数据之间的循环。此外,我们还学习了如何扩展Redux以使用多个reducers和actions以及多个连接组件。

 

However, we have yet to make an asynchronous call for off-site data. Tomorrow we'll get into how to use middleware with Redux, which will give us the ability to handle fetching remote data from within our app and still use the power of Redux to keep our data.

Good job today and see you tomorrow!

但是,我们还没有对异地数据进行异步调用。明天我们将介绍如何使用Redux中间件,这将使我们能够处理从我们的应用程序中获取远程数据,并仍然使用Redux的强大功能来保存我们的数据。

今天干得好,明天见!

学习REACT正确的方法

React和朋友的最新,深入,完整的指南。

下载第一章

❮上一个

下一章:

Redux中间件

下一个 ❯

本教程系列的完整源代码可以在GitHub repo找到,其中包括所有样式和代码示例。

如果您在任何时候感到困难,还有其他问题,请随时通过以下方式与我们联系:

猜你喜欢

转载自blog.csdn.net/qq_35812380/article/details/83338521
今日推荐