• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

Redux入门教程:将 Redux与React连接起来

这是 redux 入门系列的第三部分,在本教程中,我们将学习如何将 Redux 存储与 react 连接起来。Redux是一个独立的库,可与所有流行的前端库和框架协同工作。由于它的功能性方法,它可以与 React 完美配合

您无需遵循本系列的前面部分即可使本教程有意义。如果您在这里学习如何使用 React 和 Redux,您可以阅读下面的快速回顾,然后查看上一部分的代码并从那里开始。 

快速回顾

第一篇文章中,我们了解了 Redux 工作流程并回答了这个问题,为什么是 Redux? 我们创建了一个非常基本的演示应用程序,并向您展示了 Redux 的各种组件——actions、reducers 和 store——是如何连接的。

一篇文章中,我们开始构建一个联系人列表应用程序,该应用程序允许您添加联系人,然后将它们显示为列表。我们为我们的联系人列表创建了一个 Redux 存储,并添加了一些减速器和操作。我们尝试使用 和 之类的存储方法来分派操作并检索新store.dispatch()状态store.getState()

在本文结束时,您将了解到:

  1. 容器组件和展示组件的区别

  2. 关于 react-redux 库

  3. 如何使用绑定 react 和 reduxconnect()

  4. 如何使用mapDispatchToProps

  5. 如何使用检索状态mapStateToProps

本教程的代码可在 GitHub 上的 react-redux-demo存储库中找到。从 v2 分支获取代码并将其用作本教程的起点。如果您想知道本教程结束时应用程序的外观,请尝试 v3 分支。让我们开始吧。

设计组件层次结构:智能组件与愚蠢组件

这是您可能以前听说过的概念,但让我们快速了解一下智能组件和哑组件之间的区别。回想一下,我们为组件创建了两个单独的目录,一个名为containers/  ,另一个名为components/这种方法的好处是行为逻辑与视图分离。

表示组件被认为是愚蠢的,因为它们关心事物的外观。它们与应用程序的业务逻辑解耦,专门通过 props 从父组件接收数据和回调。如果数据来自父组件的本地状态,他们不关心您的应用程序是否连接到 Redux 存储。 

另一方面,容器组件处理行为部分,应该包含非常有限的dom标记和样式。它们将需要渲染的数据作为道具传递给哑组件。 

我在另一个教程React 中的 Stateful vs. Stateless Components 中深入讨论了这个主题。


Redux入门教程:将 Redux与React连接起来  第1张React Manjunath M 中的 React 有状态与无状态功能组件

继续,让我们看看我们将如何组织我们的组件。

Redux入门教程:将 Redux与React连接起来  第2张

表示组件

以下是我们将在本教程中使用的演示组件。 

组件/AddContactForm。jsx

import React from 'react';

const AddContactForm = ({onInputChange, onFormSubmit}) => 
    (
		<form>
			<div className="form-group">
			    <label htmlFor="emailAddress">Email address</label>
			    <input type="email" class="form-control" name="email" onChange={onInputChange} placeholder="name@example.com" />
			</div>
			
		{/* Some code omitted for brevity */}
			  
			<div className="form-group">
			    <label htmlFor="physicalAddress">Address</label>
			    <textarea className="form-control" name="address" onChange={onInputChange} rows="3"></textarea>
			</div>

			<button type="submit" onClick={onFormSubmit} class="btn btn-primary"> Submit </button>
		</form>
	)

export default AddContactForm;

这是一个用于添加新联系人的 HTML 表单。组件作为道具接收onInputChangeonFormSubmit回调。当输入值改变和表单被提交时触发onInputChange 事件。onFormSubmit

组件/ContactList.jsx

const ContactList = (props) => {
    return(	<ul className="list-group" id="contact-list">
           		{props.contactList.map(
                  (contact) => 
                  <li key={contact.email} className="list-group-item"> 
                    <ContactCard contact = {contact}/>
                  </li>
              	)}
            </ul>)
}

export default ContactList;

该组件接收一组联系人对象作为道具,因此命名为ContactList我们使用该Array.map()方法提取个人联系方式,然后将该数据传递给 <ContactCard />.

组件/ContactCard.jsx

const ContactCard = ({contact}) => {
    
	return(
        <div>
	        <div className="col-xs-4 col-sm-3">
	           {contact.photo !== undefined ?  <img src={contact.photo} alt={contact.name} className="img-fluid rounded-circle" /> :
	            						 <img src="img/profile_img.png" alt ={contact.name} className="img-fluid rounded-circle" />}
	        </div>
	        <div className="col-xs-8 col-sm-9">
	            <span className="name">{contact.name + ' ' + contact.surname}</span><br/>
	            
	            {/* Some code omitted for brevity */}
                
	        </div>
	      </div>
        
    )
}

export default ContactCard;

该组件接收一个联系人对象并显示联系人的姓名和图像。 对于实际应用,在云中托管 javascript 图像可能是有意义的

容器组件

我们还将构建准系统容器组件。

容器/Contacts.jsx

class Contacts extends Component {
 
  constructor(props) {
      super(props);
      this.returnContactList = this.returnContactList.bind(this);
  }
  returnContactList() {
    // Retrieve contactlist from the store
  }

  render() {
   
    return (
        <div>

         	<AddContact/>
         	<br />
          <ContactList contactList= {this.returnContactList()} />
        </div>
    );
  }
}


export default Contacts;

returnContactList()函数检索联系人对象数组并将其传递给 ContactList 组件。由于returnContactList()从存储中检索数据,我们暂时将该逻辑留空。

容器/AddContacts.jsx

class AddContact extends Component {
    constructor(props) {
		super(props);
		
        /* Function binding goes here. Omitted for brevity */
	}

	showAddContactBox() {
	    /* Logic for toggling ContactForm */
    }

	handleInputChange(event) {
		const target = event.target;
    	const value = target.value;
    	const name = target.name;

        /* Logic for handling Input Change */

   	}

	handleSubmit(e) {
		e.preventDefault();
	    
        /* Logic for hiding the form and update the state */
	}
    
    /* Renders the AddContactForm */
	renderForm() {
		return(
			<div className="col-sm-8 offset-sm-2">
				<AddContactForm onFormSubmit={this.handleSubmit} onInputChange={this.handleInputChange} />
 			</div>
 		)
	}
	render() {
		return(
			<div>
				
				{ /* A conditional statement goes here that checks whether the form 
                    should be displayed or not */}
			</div>
			)
	}
}


export default AddContact;

我们创建了三个对应于三个操作的基本处理程序方法。它们都派发动作来更新状态。在 render 方法中,我们省略了显示/隐藏表单的逻辑,因为我们需要获取状态。 

现在让我们看看如何将 react 和 redux 绑定在一起

react-redux 库

默认情况下,React 绑定在 Redux 中不可用。您需要先安装一个名为 react-redux 的额外库。 

npm install --save react-redux

该库仅导出您需要记住的两个api<Provider /> ,一个组件和一个称为connect()

提供者组件

像 Redux 这样的库需要让整个 React 组件树都可以访问存储数据,从根组件开始。提供者模式允许库从上到下传递数据。下面的代码演示了 Provider 如何神奇地将状态添加到组件树中的所有组件中。 

演示代码

import { Provider } from 'react-redux'

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

整个应用程序需要能够访问商店。因此,我们将提供程序包装在应用程序组件周围,然后将我们需要的数据添加到树的上下文中。然后组件的后代可以访问数据。 

connect()方法 _

现在我们已经为我们的应用程序提供了商店,我们需要将 React 连接到商店。您可以与 store 通信的唯一方法是调度操作和检索状态。我们以前曾用于store.dispatch()调度操作和store.getState()检索状态的最新快照。可以让您完全做到这connect() 一点,但需要借助称为mapDispatchToProps和的两种方法mapStateToProps我在下面的示例中演示了这个概念:

演示代码

import {connect} from 'react-redux'

const AddContact = ({newContact, addContact}) => {
  return (
    <div>
      {newContact.name} <br />
      {newContact.email} <br />
      {newContact.phone} <br />
      
      Are you sure you want to add this contact?
      <span onClick={addContact}> Yes </span>
    </div>
  )
}

const mapStateToProps = state => {
  return {
    newContact : state.contacts.newContact
  }
}

const mapDispatchToProps = dispatch => {
  return {
    addContact : () => dispatch(addContact())
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps

mapStateToProps并且mapDispatchToProps都返回一个对象,这个对象的键成为连接组件的一个道具。例如,state.contacts.newContact映射到props.newContact动作创建者 addContact()映射到props.addContact.  

但要使其正常工作,您需要上面代码片段中的最后一行。 

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(AddContact)

我们不是直接导出 AddContact 组件,而是导出一个连接的组件。连接提供addContactnewContact作为<AddContact/>组件的道具。 

如何连接 React 和 Redux

接下来,我们将介绍连接 React 和 Redux 所需遵循的步骤。

安装 react-redux 库

如果你还没有安装 react-redux 库。你可以使用 NPM 或 Yarn 来安装它。 

npm install react-redux --save

将 Store 提供给您的 App 组件

首先创建商店。然后,通过将 store 对象作为 prop 传递给<Provider />.

index.js

import React from 'react';
import {render}from 'react-dom';
import { Provider } from 'react-redux'
import App from './App';

import configurestore from './store'

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

将 React 容器连接到 Redux

connect 函数用于将 React 容器绑定到 Redux。这意味着您可以使用连接功能:

  1. 订阅商店并将其状态映射到您的道具

  2. 调度动作并将调度回调映射到你的道具

将应用程序连接到 Redux 后,您可以使用它 this.props 来访问当前状态并分派操作。我将在 AddContact 组件上演示该过程。AddContact需要调度三个动作并从存储中获取两个属性的状态。让我们看一下代码。

首先, connect 导入 AddContact.jsx

import { connect } from 'react-redux';

其次,创建两个方法: mapStateToProps 和 mapDispatchToProps

function mapStateToProps(state) {
    return {

        isHidden : state.ui.isAddContactFormHidden,
        newContact: state.contacts.newContact
    }
}

function mapDispatchToProps(dispatch) {
    return {
        onFormSubmit: (newContact) => {
           dispatch(addContact(newContact));
        },
        onInputChange: (name,value) => {
    
            dispatch(handleInputChange(name,value));
        },

        onToggle: () => {
            dispatch(toggleContactForm());
        }
    }
}

mapStateToProps 接收商店的状态作为参数。它返回一个对象,该对象描述了 store 的状态如何映射到你的 props 中。 mapDispatchToProps 返回一个类似的对象,该对象描述了调度操作如何映射到您的道具。 

最后,我们使用 connect 将 AddContact 组件绑定到这两个函数如下:

export default connect(mapStateToProps, mapDispatchToProps) (AddContact)

更新容器组件以使用道具

组件的 props 现在可以从 store 中读取 state 和 dispatch action。handeInputChange逻辑应更新如下:handleSubmitshowAddContactBox

  showAddContactBox() {
        const { onToggle }  = this.props;
		onToggle();
	}

	handleInputChange(event) {
		const target = event.target;
    	const value = target.value;
    	const name = target.name;

   		const { onInputChange } = this.props;
		onInputChange(name,value); 
   	}

	handleSubmit(e) {
		e.preventDefault();
		this.props.onToggle();
		this.props.onFormSubmit();
	}

我们已经定义了处理程序方法,但仍然缺少一个部分——render函数内部的条件语句。

render() {
    return(
		<div>			
			{ this.props.isHidden === false ? this.renderForm(): <button onClick={this.showAddContactBox} className="btn"> Add Contact </button>}
		</div>
	)
}

如果isHidden为 false,则呈现表单。否则,将呈现一个按钮。 

显示联系人

我们已经完成了最具挑战性的部分。现在,剩下的就是将这些联系人显示为列表。Contacts容器是该逻辑的最佳位置 

import React, { Component } from 'react';
import { connect } from 'react-redux'; 
/* Component import omitted for brevity */

class Contact extends Component {

  constructor(props) {
    super(props);
    this.returnContactList = this.returnContactList.bind(this);
  }

   returnContactList() {
    return this.props.contactList;
  }


  render() {

   
    return (
        <div>
     		<br />
         	<AddContact/>
         	<br />
          <ContactList contactList= {this.returnContactList()} />
        </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    contactList : state.contacts.contactList,
    
  }
}


export default connect(mapStateToProps, null) (Contact);

我们已经完成了与上面连接联系人组件与 Redux 存储相同的过程。mapStateToProps函数将商店对象映射到contactList道具。然后我们使用 connect 将 props 值绑定到 Contact 组件。connect 的第二个参数为 null,因为我们没有任何要调度的操作。这样就完成了我们的应用程序与 Redux 商店状态的集成。 



文章目录
  • 快速回顾
  • 设计组件层次结构:智能组件与愚蠢组件
  • 表示组件
      • 组件/AddContactForm。jsx
      • 组件/ContactList.jsx
      • 组件/ContactCard.jsx
  • 容器组件
      • 容器/Contacts.jsx
      • 容器/AddContacts.jsx
  • react-redux 库
    • 提供者组件
      • 演示代码
    • connect()方法 _
      • 演示代码
  • 如何连接 React 和 Redux
    • 安装 react-redux 库
    • 将 Store 提供给您的 App 组件
      • index.js
    • 将 React 容器连接到 Redux
    • 更新容器组件以使用道具
  • 显示联系人