- vừa được xem lúc

Sử dụng recoil thay thế redux ?

0 0 184

Người đăng: Phan Van Hung

Theo Viblo Asia

Như chúng ta đã biết quản lí state trong react đôi lúc rất khó khăn đó là lí do tại sao chúng ta sử dụng redux hoặc một số thư viện khác như mobx để giúp việc quản lí state trở nên dễ dàng hơn. Recoil cũng là một thư viện quản lí state được mô phỏng chặt chẽ theo các API của react hook. Nó cho phép chúng ta khai báo state bằng atom và tính toán state bằng selector. Nếu bạn muốn tìm hiều về những hạn chế mà team Facebook phải đối mặt, và cách họ giải quyết bằng recoil thì có thể theo dõi trên video này.

Một lưu ý quan trọng: Mặc dù nhiều công ty bao gồm cả Facebook đang sử dụng recoil, nhưng nó chỉ đang ở trạng thái thử nghiệm. Các API và chức năng của nó có thể thay đổi.

Trong bài viết này, mình sẽ hướng dẫn các bạn chuyển từ redux sang recoil đồng thời so sánh sự khác biệt giữa chúng. Mình sẽ làm việc với ví dụ TodoMVC từ Github của redux. App của chúng ta sẽ hoạt động như thế này

Cài đặt recoil

Bước đầu tiên để sử dụng bất kì một thư viện Javascript nào là thêm nó vào project. Bạn có thể tham chiếu đến thư viện bằng HTML <script /> hoặc cài đặt thông qua npm , yarn. Tương tự như redux, chúng ta sẽ bọc component root bằng một provider do recoil cung cấp <RecoilRoot />.

Mở src/index.js và import thư viện recoil.

import { RecoilRoot } from "recoil";

Và update hàm render như sau

render( <RecoilRoot> <App /> </RecoilRoot>, document.getElementById("root")
);
Khai báo và cập nhật state

Để khai báo state chúng ta dùng atom. Trong ví dụ Todo, chúng ta cần lưu trữ một danh sách các công việc cần làm, mình sẽ tạo một atom với một state mặc định. Tạo một thư mục recoil và một file todos với nội dung như sau

import { atom } from "recoil"; export const todos = atom({ key: "todos", default: [],
});

Bây giờ, mở component/Header.js và sửa code với nội dung

import React from "react";
import TodoTextInput from "./TodoTextInput";
import { useSetRecoilState } from "recoil";
import { todos } from "../recoil/todos"; const Header = () => { const setTodos = useSetRecoilState(todos); const save = (text) => { if (text.length !== 0) { setTodos((todos) => [ ...todos, { id: Date.now(), text, completed: false, }, ]); } }; return ( <header className="header"> <h1>todos</h1> <TodoTextInput newTodo onSave={save} placeholder="What needs to be done?" /> </header> );
}; export default Header;

component này sẽ hiển thị một text input dùng cho việc nhập công việc cần làm và lưu trữ chúng. Để thêm mới một công việc, chúng ta cần một function để update danh sách công việc nơi đã tạo state todos. Chúng ta dùng hook useSetRecoilState để lấy một làm setter được sử dụng trong hàm save().

Nếu bạn so sánh nó với redux, thì bạn sẽ không cần tạo action creatorreducers để update state và sau đó kết nối component với redux storedispatch action. Trong Recoil bạn sử dụng atom để lưu state, và dùng các hook API để tương tác với state. Nếu bạn là người mới sử dụng React và hiểu về hooks API, thì sẽ nhanh chóng nắm bắt được Recoil vì nó được mô phỏng chặt chẽ với API của React, không giống như Redux - bạn cần hiểu luồng dữ liệu một chiều của nó.

Tính toán state

Phần tiếp theo chúng ta sẽ update <MainSection />. Nó hiển thị một đầu vào để đánh dấu tất cả các việc cần làm là đã hoàn thành và cũng có hai thành phần bổ sung mà chúng ta sẽ nói đến sau. Mơ đường dẫn componenrs/MainSection.js và update code với nội dung như sau

import React from "react";
import { useRecoilValue, useRecoilState } from "recoil";
import Footer from "./Footer";
import VisibleTodoList from "../containers/VisibleTodoList";
import { completedTodoCount, todos } from "../recoil/todos"; const MainSection = () => { const completedCount = useRecoilValue(completedTodoCount); const [todoList, setTodoList] = useRecoilState(todos); const todosCount = todoList.length; const clearCompleted = () => { setTodoList((previousTodos) => previousTodos.filter((todo) => todo.completed === false) ); }; const completeAllTodos = () => setTodoList((previousTodos) => { const areAllMarked = previousTodos.every((todo) => todo.completed); return previousTodos.map((todo) => ({ ...todo, completed: !areAllMarked, })); }); return ( <section className="main"> {!!todosCount && ( <span> <input className="toggle-all" type="checkbox" checked={completedCount === todosCount} readOnly /> <label onClick={completeAllTodos} /> </span> )} <VisibleTodoList /> {!!todosCount && ( <Footer completedCount={completedCount} activeCount={todosCount - completedCount} onClearCompleted={clearCompleted} /> )} </section> );
}; export default MainSection;

Những gì bạn thấy ở trên là thay vì kêt nối với store bằng mapStateToPropsmapDispatchToProps như redux thì chúng ta sẽ dùng hooks API useRecoilValueuseRecoilState. useRecoilValue dùng để đọc nội dung của state, trong trương hợp này là một selector completedTodoCount. Chúng ta sẽ khai báo một hàm completedTodoCount. Hàm này sẽ là hàm tính toán từ state, vì vậy nó được gọi là selector trong recoil. Mở recoil/todos.js và import selector từ module recoil.

import { atom, selector } from "recoil";

Sau đó khai báo selector như bên dưới:

export const completedTodoCount = selector({ key: "completedTodoCount", get: ({ get }) => { const list = get(todos); return list.reduce( (count, todo) => (todo.completed ? count + 1 : count), 0 ); },
});

Để khai báo một selector ban gọi function selector() với một object gồm tên của trạng thái và function get() sẽ tính toán và trả về một giá trị. Function này sẽ nhận một đối tượng có hàm get() có thể sử dụng để lấy dữ liệu từ các atom hoặc selector khác.

Lọc dữ liệu todos

Tới đây, chúng ta đã nắm được hầu hết các khái niệm cơ bản về Recoil và bạn có thể thấy nó khác với Redux như thế nào. Phần còn lại của bài viết là làm cho ứng dụng hoạt động đầy đủ các chức năng bằng cách sử dụng recoil. <FilterLink /> là component tiếp theo chúng ta sẽ triển khai. Mở containers/FilterLink.js và sửa lại code như dưới:

import React from "react";
import { useRecoilState } from "recoil";
import Link from "../components/Link";
import { visibilityFilter } from "../recoil/todos"; export default ({ filter, children }) => { const [visibility, setVisibilityFilter] = useRecoilState(visibilityFilter); const setFilter = () => setVisibilityFilter(filter); return ( <Link active={filter === visibility} setFilter={setFilter} children={children} /> );
};

Mở recoil/todos.js và thêm function như bên dưới

import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE,
} from "../constants/TodoFilters"; export const visibilityFilter = atom({ key: "visibilityFilter", default: SHOW_ALL,
}); 
Hiển thị todos

Điều tiếp theo, là hiển thị các công việc dựa trên bộ lọc. Để làm được điều đó, chúng ta sẽ thêm mới một selector và sửa component VisibleTodoList. Trong khi bạn vẫn đang ở recoil/todos.js , hãy thêm mới một selector như sau

export const filteredTodos = selector({ key: "filteredTodos", get: ({ get }) => { const filter = get(visibilityFilter); const list = get(todos); switch (filter) { case SHOW_COMPLETED: return list.filter((t) => t.completed); case SHOW_ACTIVE: return list.filter((t) => !t.completed); default: return list; } },
});

Mở containers/VisibleTodoList.js và sửa như sau

import React from "react";
import TodoList from "../components/TodoList";
import { filteredTodos, todos } from "../recoil/todos";
import { useRecoilValue, useSetRecoilState } from "recoil"; const VisibleTodoList = () => { const filteredTodoList = useRecoilValue(filteredTodos); const setTodos = useSetRecoilState(todos); const completeTodo = (todoId) => { setTodos((previousTodos) => previousTodos.map((todo) => todo.id === todoId ? { ...todo, completed: !todo.completed } : todo ) ); }; const deleteTodo = (todoId) => { setTodos((previousTodos) => previousTodos.filter((todo) => todo.id !== todoId) ); }; const editTodo = (todoId, text) => { setTodos((previousTodos) => previousTodos.map((todo) => todo.id === todoId ? { ...todo, text } : todo ) ); }; return ( <TodoList filteredTodos={filteredTodoList} actions={{ completeTodo, deleteTodo, editTodo }} /> );
}; export default VisibleTodoList;

OK! vậy là chúng ta đã biết được một số khái niệm cơ bản của recoil trong việc chuyển cách sử dụng redux sang recoil thông qua ví dụ todos. Mình nghĩ sau này thư viện sẽ trở thành trending nếu nó hoàn thiện hơn, nên việc tìm hiểu nó trước sẽ là một lợi thế :v. Còn việc nó có thể thay thế redux hay một số thư viện quản lí state khác hay không thì mình không nói trước được :v. Cuối cùng, cảm ơn mọi người đã theo dõi bài viết. (thanks)

Bài viết có tham khảo tại: How to switch from redux to recoil

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu cơ bản về Python (P1)

Hello, xin chào mọi người, mình là một dev FE, nhưng mấy hôm nay thấy hứng thú với python nên quyết định làm 1 series về những gì mà mình học được. Lưu ý là những chia sẽ của mình cũng là một thằng bắ

0 0 25

- vừa được xem lúc

Kiến thức aws vụn vặt.

Cloud computing. Cloud computing được định nghĩa như sau: Cloud computing là điện toán đám mây, cung cấp tài nguyên IT theo yêu cầu thông qua Internet.

0 0 25

- vừa được xem lúc

Tổng quan về kiểm thử tự động: Định nghĩa, lợi ích, quy trình, các loại hình và cách áp dụng vào dự án

1. Kiểm thử tự động là gì. 2. Các lý do sau đây sẽ giúp bạn hiểu rõ hơn về tầm quan trọng của kiểm thử tự động:.

0 0 14

- vừa được xem lúc

Ứng dụng Kiểm Thử Tự Động vào nhóm dự án Agile

Phương pháp phát triển phần mềm theo triết lý/mô hình Agile đang ngày càng trở nên phổ biến trên khắp thế giới. Các công ty, doanh nghiệp và nhóm dự án vì thế cũng cần một cách thức kiểm thử phần mềm

0 0 19

- vừa được xem lúc

Tool testing guide for new Python developer

Lời mở đầu. Hello everyone, long time no see, nay tôi sẽ trở lại với bài dịch liên quan đến một bước crucial trong software development.

0 0 18

- vừa được xem lúc

System Design - Nguyên tắc cơ bản về thiết kế hệ thống

Trong bài viết này, chúng ta sẽ đi tìm hiểu về cái khái niệm, nguyên tắc cơ bản trong thiết kế hệ thống (system design) như là: khả năng mở rộng (scalability), thông lượng (throughput), băng thông (ba

0 0 8