Thứ tư, 13/06/2018 | 00:00 GMT+7

Kết nối Redux với React bằng React Redux


Redux là một thực thể riêng biệt với React và được dùng với bất kỳ khung công tác JavaScript front-end nào hoặc với JavaScript vani. Tuy nhiên, không thể phủ nhận rằng React và Redux rất thường được sử dụng cùng nhau, và vì vậy, thư viện React Redux cung cấp các ràng buộc đơn giản giúp kết nối cả hai rất dễ dàng.

API cho các liên kết React Redux rất đơn giản: một thành phần Nhà cung cấp giúp cửa hàng của ta có thể truy cập được trong toàn bộ ứng dụng của ta và một hàm kết nối tạo ra các thành phần containers có thể đọc trạng thái từ cửa hàng và gửi các hành động.

Bắt đầu

Hãy khởi tạo một dự án React và đảm bảo ta có các phụ thuộc cần thiết. Hãy sử dụng Create React App để tạo một ứng dụng quản lý dấu trang mẫu:

$ npx create-react-app fancy-bookmarks

Lưu ý ở đây việc sử dụng npx đảm bảo ta đang sử dụng version Tạo ứng dụng React mới nhất.

Bây giờ, hãy cd vào folder của ứng dụng của ta và thêm các gói reduxreact-redux :

$ yarn add redux react-redux

# or, using npm:
$ npm install redux react-redux

Cài đặt Redux

Bây giờ ta hãy cài đặt Redux cho ứng dụng của ta . Tôi sẽ không giải thích nhiều ở đây bởi vì, nhưng nếu bạn mới sử dụng Redux nói chung, hãy xem phần giới thiệu của ta về Redux .

Đầu tiên, một số loại hành động:

hành động / loại.js
export const ADD_BOOKMARK = 'ADD_BOOKMARK';
export const DELETE_BOOKMARK = 'DELETE_BOOKMARK';

Và một số người tạo hành động đồng hành với các loại hành động của ta :

hành động / index.js
import uuidv4 from 'uuid/v4';
import { ADD_BOOKMARK, DELETE_BOOKMARK } from './types';

export const addBookmark = ({ title, url }) => ({
  type: ADD_BOOKMARK,
  payload: {
    id: uuidv4(),
    title,
    url
  }
});

export const deleteBookmark = id => ({
  type: DELETE_BOOKMARK,
  payload: {
    id
  }
});

Ở đây bạn sẽ lưu ý tôi cũng đang sử dụng thư viện uuid để tạo ID ngẫu nhiên.


Và đây là công cụ giảm thiểu duy nhất cần thiết cho ứng dụng đơn giản của ta :

giảm thiểu / index.js
import { ADD_BOOKMARK, DELETE_BOOKMARK } from '../actions/types';

export default function bookmarksReducer(state = [], action) {
  switch (action.type) {
    case ADD_BOOKMARK:
      return [...state, action.payload];
    case DELETE_BOOKMARK:
      return state.filter(bookmark => bookmark.id !== action.payload.id);
    default:
      return state;
  }
}

Như bạn thấy , cho đến nay ta hoàn toàn đang ở Redux-land và chưa làm bất cứ điều gì để khiến ứng dụng React của ta kết nối liền mạch với cửa hàng Redux của ta . Đây là những gì ta sẽ giải quyết tiếp theo.

Thành phần nhà cung cấp

Ta sẽ sử dụng thành phần Nhà cung cấp từ React Redux để bao bọc thành phần Ứng dụng chính của ta và làm cho cửa hàng Redux của ứng dụng có thể truy cập được từ bất kỳ thành phần containers nào (thành phần được kết nối) trong cây thành phần React:

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './reducers';

import App from './App';

const store = createStore(rootReducer);

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

Nếu bạn đang sử dụng React Router, bạn sẽ bọc thành phần Nhà cung cấp xung quanh thành phần BrowserRouter .

Thành phần containers & chức năng kết nối

Như vậy, cửa hàng Redux đã có thể truy cập được trong ứng dụng của ta , ta vẫn cần tạo một số thành phần containers , còn gọi là các thành phần được kết nối sẽ có quyền truy cập để đọc từ cửa hàng hoặc hành động gửi. Ta sẽ tạo hai thành phần containers : AddBookmarkBookmarkList và thành phần Ứng dụng của ta sẽ sử dụng chúng và trông giống như sau:

App.js
import React, { Component } from 'react';
import AddBookmark from './containers/AddBookmark';
import BookmarksList from './containers/BookmarksList';

class App extends Component {
  render() {
    return (
      <div>
        <AddBookmark />
        <BookmarksList />
      </div>
    );
  }
}

export default App;

Bây giờ đối với thành phần containers đầu tiên của ta , thành phần BookmarksList :

container / BookmarksList.js
import React from 'react';
import { connect } from 'react-redux';
import Bookmark from '../components/Bookmark';
import { deleteBookmark } from '../actions';

function BookmarksList({ bookmarks, onDelete }) {
  return (
    <div>
      {bookmarks.map(bookmark => {
        return (
          <Bookmark bookmark={bookmark} onDelete={onDelete} key={bookmark.id} />
        );
      })}
    </div>
  );
}

const mapStateToProps = state => {
  return {
    bookmarks: state
  };
};

const mapDispatchToProps = dispatch => {
  return {
    onDelete: id => {
      dispatch(deleteBookmark(id));
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(BookmarksList);

Ta sử dụng chức năng kết nối của React Redux và chuyển vào trong một hàm mapStateToProps và một hàm mapDispatchToProps . Sau đó, ta gọi hàm trả về với thành phần mà ta muốn kết nối.

mapStateToProps nhận giá trị hiện tại của trạng thái và sẽ trả về một đối tượng làm cho các phần của trạng thái có sẵn dưới dạng đạo cụ cho thành phần được kết nối. Ở đây trạng thái của ta chỉ có dấu trang, nhưng bạn có thể tưởng tượng một tình huống mà nhiều phần trạng thái có thể được ánh xạ với các đạo cụ khác nhau. Ví dụ:

const mapStateToProps = state => {
  return {
    users: state.users,
    todos: state.todos,
    // ...
  };
};

mapStateToProps nhận phương thức điều phối của cửa hàng và sẽ trả về một đối tượng làm cho một số lệnh gọi lại khả dụng dưới dạng đạo cụ sau đó gửi các hành động mong muốn đến cửa hàng.


Tiếp theo, thành phần AddBookmark :

container / AddBookmark.js
import { connect } from 'react-redux';
import { addBookmark } from '../actions';
import NewBookmark from '../components/NewBookmark';

const mapDispatchToProps = dispatch => {
  return {
    onAddBookmark: bookmark => {
      dispatch(addBookmark(bookmark));
    }
  };
};

export default connect(
  null,
  mapDispatchToProps
)(NewBookmark);

Thành phần này không cần đọc từ cửa hàng, vì vậy ta chuyển vào null làm đối số đầu tiên cho hàm kết nối.

Bạn cũng sẽ nhận thấy rằng thành phần thành phần containers thứ hai này không hiển thị bất kỳ thứ gì của riêng nó, và thay vào đó, tất cả phần kết xuất giao diện user được để lại cho thành phần trình bày NewBookmark .

Các thành phần thuyết trình

Các thành phần trình bày đơn giản hơn nhiều và không có quyền truy cập trực tiếp vào cửa hàng. Thay vào đó, họ nhận được đạo cụ từ các thành phần containers có giá trị từ trạng thái hoặc lệnh gọi lại gọi người tạo hành động của ta . Họ không cần biết bất cứ điều gì về Redux, và thay vào đó họ chỉ là một chức năng của các đạo cụ được trao cho họ. Các thành phần trình bày rất đơn giản để viết, dễ dàng sử dụng lại và dễ kiểm tra.

Ví dụ: đây là thành phần trình bày Dấu trang của ta , thành phần này hiển thị một dấu trang:

component / Bookmark.js
import React from 'react';

const styles = {
  borderBottom: '2px solid #eee',
  background: '#fafafa',
  margin: '.75rem auto',
  padding: '.6rem 1rem',
  maxWidth: '500px',
  borderRadius: '7px'
};

export default ({ bookmark: { title, url, id }, onDelete }) => {
  return (
    <div style={styles}>
      <h2>{title}</h2>
      <p>URL: {url}</p>
      <button type="button" onClick={() => onDelete(id)}>
        Remove
      </button>
    </div>
  );
};

Như bạn thấy , nó nhận được dấu trang cũng như lệnh gọi lại onDelete dưới dạng đạo cụ.


Trong trường hợp của NewBookmark , nó không phải là một thành phần trình bày thuần túy, mà là một thành phần kết hợp nhiều hơn vì nó giữ một số trạng thái local cho các giá trị đầu vào. Tuy nhiên, thành phần này hoàn toàn không biết về Redux:

thành phần / NewBookmark.js
import React from 'react';

class NewBookmark extends React.Component {
  state = {
    title: '',
    url: ''
  };

  handleInputChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  handleSubmit = e => {
    e.preventDefault();
    if (this.state.title.trim() && this.state.url.trim()) {
      this.props.onAddBookmark(this.state);
      this.handleReset();
    }
  };

  handleReset = () => {
    this.setState({
      title: '',
      url: ''
    });
  };

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="title"
          name="title"
          onChange={this.handleInputChange}
          value={this.state.title}
        />
        <input
          type="text"
          placeholder="URL"
          name="url"
          onChange={this.handleInputChange}
          value={this.state.url}
        />
        <hr />
        <button type="submit">Add bookmark</button>
        <button type="button" onClick={this.handleReset}>
          Reset
        </button>
      </form>
    );
  }
}

export default NewBookmark;

Và đó là tất cả những gì cần làm! Ứng dụng quản lý dấu trang đơn giản của ta đang hoạt động, lấy dữ liệu từ cửa hàng và gửi các hành động.

🏇 Với điều này, bạn nên tham gia các cuộc đua! Để có một chủ đề khác, bạn cũng có thể xem các tài liệu chính thức .


Tags:

Các tin liên quan