Tớ đã ăn hành với Redux như thế nào?

4727

Để chuẩn bị cho công cuộc phỏng vấn vì miếng ăn, tớ phải tranh thủ tìm hiểu React và các công nghệ liên quan, trong đó có Redux. Đường cách mạng còn lắm gian truân, đọc document của nó éo hiểu gì hết. Hôm nay chia sẻ với mọi người cách tiếp cận Redux.

Đặt vấn đề

Khi lập trình React, điều đầu tiên bực bội nhất là việc quản lý State. Như hình phía trên, để truyền dữ liệu giữa các component khá là lằng nhằng do chỉ truyền được cho component kề nhau. Do đó, cần có một cơ chế để quản lý state riêng biệt.

Giải pháp

Ok, dễ nhất thì ta cứ xem state như biến toàn cục, khi cần thì viết Get/Set bình thường. Tớ có nghĩ đến localStorage. Tuy nhiên cách này khá bưởi, bạn có thể xem thêm tại đây.
Please Stop Using Local Storage

Thử cách khác, ta hỏi chị Google. Kết quả là ta được 2 giải pháp đó là Flux và Redux. Về phần Flux, ta có thể xem bài tutorial sau đây là hình dung được tư tưởng. Còn Redux, nó khá là hại não.
Xem bài Hướng dẫn và giải thích Flux bằng hình vẽ

Redux

Giờ mới là phần chính. Ta thử vào xem trang chủ của Redux tại https://redux.js.org xem có hiểu gì không nhé. Chắc cú là không dành cho beginner rồi. Tớ phải xem bài viết React Redux Tutorial for Beginners: The Definitive Guide (2018) mới hình dung được Redux như thế nào.

Về cơ bản, Redux là một thư viện quản lý state, nó độc lập với React. Do đó, Redux có thể sử dụng chung với các thư viện khác vẫn được.

Các thành phần cơ bản của Redux bao gồm:

  • Store – Nơi lưu trữ state
  • Actions – Các hành động truyền dữ liệu được gởi từ ứng dụng đến Store
  • Reducer – Xác định cách thay đổi State

Redux flow

Ăn hành

Bây giờ tớ sẽ minh hoạ cho các bạn hiểu cách chạy bình thường của Redux nhé. Lúc này, ta chỉ đụng mỗi Redux thôi.

Initial

Đầu tiên, Reducer sẽ khởi tạo State và cách xác định thay đổi State. Sau đó, khởi tạo Store bằng Reducer đã khởi tạo trước đó. Lúc này, ta khai báo tiếp hành động.

import { ADD_ARTICLE } from ‘../constants/action-types’
const initialState = {
articles: []
}
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_ARTICLE:
return {state, articles: [state.articles, action.payload] }
default:
return state
}
}
export default rootReducer
view rawredux__reducer.js hosted with ❤ by GitHub
import { createStore } from ‘redux’
import { rootReducer } from ‘../reducers/index’
const store = createStore(rootReducer)
export default store
view rawredux__store.js hosted with ❤ by GitHub
import { ADD_ARTICLE } from ‘../constants/action-types’
export const addArticle = article => ({ type: ADD_ARTICLE, payload: article })
view rawredux_actions.js hosted with ❤ by GitHub

Quá trình khởi tạo đã hoàn tất, ta khởi tạo tiếp một chút để bắt đầu test.

import store from ‘../js/store/index’
import { addArticle } from ‘../js/actions/index’
window.store = store
window.addArticle = addArticle
view rawredux__init.js hosted with ❤ by GitHub

Bây giờ, bạn thử chạy đoạn code dưới đây ở Developer Tool.

store.getState()
// Output: {articles: Array(0)}
store.subscribe(() => console.log(‘Look ma, Redux!!’))
store.dispatch( addArticle({ name: ‘React Redux Tutorial for Beginners’, id: 1 }) )
// Output: Look ma, Redux!!
store.getState()
// Output: {articles: Array(1)}
view rawredux__testing.js hosted with ❤ by GitHub

Running Redux

Như bạn đã thấy, phía Store sẽ dispatch thằng ku Actions là State được thay đổi rồi. Như thế, ta có thể cho State tách biệt khỏi mớ Components.

Ăn hành cùng với React

Ban đầu tớ nghĩ chúng ta có thể import Store vào nơi cần gọi là được. Nhưng giang hồ dùng chiêu thức khác, họ mapping State của Components với State của Store. Thặc vi diệu!!!

Để triển được chiêu thức đó, ta cần cài thêm package react-redux. Ghi nhớ khẩu quyết của chiêu thức này.

  • mapStateToProps – dùng để map State của Component với State trong Store của Redux
  • mapDispatchToProps – dùng để map method của Component với lời gọi action từ Store tới Actions của Redux

Sau đây là cách sử dụng.

import React from “react”;
import { connect } from “react-redux”;
import PropTypes from “prop-types”;
const mapStateToProps = state => {
return { articles: state.articles };
};
const ConnectedList = ({ articles }) => (
<ul className=“list-group list-group-flush”>
{articles.map(el => (
<li className=“list-group-item” key={el.id}>
{el.title}
</li>
))}
</ul>
);
const List = connect(mapStateToProps)(ConnectedList);
ConnectedList.propTypes = {
articles: PropTypes.array.isRequired
};
export default List;
import React, { Component } from “react”;
import { connect } from “react-redux”;
import PropTypes from “prop-types”;
import uuidv1 from “uuid”;
import { addArticle } from “../actions/index”;
const mapDispatchToProps = dispatch => {
return {
addArticle: article => dispatch(addArticle(article))
};
};
class ConnectedForm extends Component {
constructor() {
super();
this.state = {
title: “”
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const { title } = this.state;
const id = uuidv1();
this.props.addArticle({ title, id });
this.setState({ title: “” });
}
render() {
const { title } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className=“form-group”>
<label htmlFor=“title”>Title</label>
<input
type=“text”
className=“form-control”
id=“title”
value={title}
onChange={this.handleChange}
/>
</div>
<button type=“submit” className=“btn btn-success btn-lg”>
SAVE
</button>
</form>
);
}
}
const Form = connect(null, mapDispatchToProps)(ConnectedForm);
ConnectedForm.propTypes = {
addArticle: PropTypes.func.isRequired
};
export default Form;

Chốt hạ

Hy vọng với cách trình bày của mình, các bạn hình dung được tư tưởng của Redux, cách dùng Redux với React như thế nào.

TopDev via Vhnam.github

Báo cáo bài viết vi phạm bản quyền>>