Thứ hai, 05/10/2020 | 00:00 GMT+7

Cách gọi API web với useEffect Hook trong React

Trong phát triển React , giao diện lập trình ứng dụng web (API) là một phần không thể thiếu trong các thiết kế ứng dụng một trang (SPA) . API là cách chính để các ứng dụng giao tiếp theo chương trình với server để cung cấp cho user dữ liệu thời gian thực và lưu các thay đổi của user . Trong các ứng dụng React, bạn sẽ sử dụng các API để tải các tùy chọn của user , hiển thị thông tin user , tìm nạp cấu hình hoặc thông tin bảo mật và lưu các thay đổi trạng thái ứng dụng.

Trong hướng dẫn này, bạn sẽ sử dụng useEffectuseState Hooks để tìm nạp và hiển thị thông tin trong ứng dụng mẫu, sử dụng server JSON làm API local cho mục đích thử nghiệm. Bạn sẽ tải thông tin khi một thành phần được mount lần đầu tiên và lưu dữ liệu đầu vào của khách hàng bằng một API. Bạn cũng sẽ làm mới dữ liệu khi user thực hiện thay đổi và học cách bỏ qua các yêu cầu API khi một thành phần ngắt kết nối. Đến cuối hướng dẫn này, bạn có thể kết nối các ứng dụng React của bạn với nhiều API khác nhau và bạn có thể gửi và nhận dữ liệu thời gian thực.

Yêu cầu

Bước 1 - Tạo dự án và API local

Trong bước này, bạn sẽ tạo API REST local bằng server JSON , server này sẽ sử dụng làm nguồn dữ liệu thử nghiệm. Sau đó, bạn sẽ xây dựng một ứng dụng để hiển thị danh sách hàng tạp hóa và thêm các mặt hàng vào danh sách. Server JSON sẽ là API local của bạn và sẽ cung cấp cho bạn một URL trực tiếp để thực hiện các yêu cầu GETPOST . Với API local , bạn có cơ hội tạo mẫu và thử nghiệm các thành phần trong khi bạn hoặc một group khác phát triển các API trực tiếp.

Đến cuối bước này, bạn có thể tạo các API giả local mà bạn có thể kết nối với các ứng dụng React của bạn .

Trên nhiều group nhanh nhẹn , group giao diện user và API làm việc song song với một vấn đề. Để phát triển ứng dụng giao diện user trong khi API từ xa vẫn đang được phát triển, bạn có thể tạo version local mà bạn có thể sử dụng trong khi đợi API từ xa hoàn chỉnh.

Có nhiều cách để tạo một API local giả. Bạn có thể tạo một server đơn giản bằng Node hoặc một ngôn ngữ khác, nhưng cách nhanh nhất là sử dụng gói JSON server Node. Dự án này tạo một API REST local từ tệp JSON .

Để bắt đầu, hãy cài đặt json-server :

  • npm install --save-dev json-server

Khi quá trình cài đặt hoàn tất, bạn sẽ nhận được thông báo thành công:

Output
+ json-server@0.16.1 added 108 packages from 40 contributors and audited 1723 packages in 14.505s 73 packages are looking for funding run `npm fund` for details found 0 vulnerabilities

json-server tạo một API dựa trên một đối tượng JavaScript . Các khóa là các đường dẫn URL và các giá trị được trả về dưới dạng phản hồi. Bạn lưu trữ local đối tượng JavaScript và commit nó với quyền kiểm soát nguồn của bạn.

Mở một file có tên db.json trong folder root của ứng dụng của bạn. Đây sẽ là JSON lưu trữ thông tin bạn yêu cầu từ API:

  • nano db.json

Thêm một đối tượng với khóa của list và một mảng giá trị với một id và một khóa của item . Điều này sẽ liệt kê các mặt hàng cho danh sách tạp hóa. list khóa cuối cùng sẽ cung cấp cho bạn một URL có điểm cuối là /list :

api-tutorial / db.json
{   "list": [     { "id": 1, "item": "bread" },     { "id": 2, "item": "grapes" }   ] } 

Trong đoạn mã này, bạn có breadgrapes được mã hóa cứng làm điểm bắt đầu cho danh sách hàng tạp hóa của bạn .

Lưu và đóng file . Để chạy server API, bạn sẽ sử dụng json-server từ dòng lệnh với một điểm đối số đến file cấu hình API. Thêm nó dưới dạng một tập lệnh trong package.json của bạn.

Mở package.json :

  • nano package.json

Sau đó, thêm một tập lệnh để chạy API. Ngoài ra, hãy thêm một thuộc tính delay . Điều này sẽ làm giảm phản hồi, tạo ra độ trễ giữa yêu cầu API của bạn và phản hồi API. Điều này sẽ cung cấp cho bạn một số thông tin chi tiết về cách ứng dụng sẽ hoạt động khi chờ phản hồi của server . Thêm delay 1500 mili giây. Cuối cùng, chạy API trên cổng 3333 bằng cách sử dụng tùy chọn -p để nó không xung đột với tập lệnh chạy create-react-app :

api-tutorial / package.json
{   "name": "do-14-api",   "version": "0.1.0",   "private": true,   "dependencies": {     "@testing-library/jest-dom": "^4.2.4",     "@testing-library/react": "^9.3.2",     "@testing-library/user-event": "^7.1.2",     "react": "^16.13.1",     "react-dom": "^16.13.1",     "react-scripts": "3.4.3"   },   "scripts": {     "api": "json-server db.json -p 3333 --delay 1500",     "start": "react-scripts start",     "build": "react-scripts build",     "test": "react-scripts test",     "eject": "react-scripts eject"   },   "eslintConfig": {     "extends": "react-app"   },   "browserslist": {     "production": [       ">0.2%",       "not dead",       "not op_mini all"     ],     "development": [       "last 1 chrome version",       "last 1 firefox version",       "last 1 safari version"     ]   },   "devDependencies": {     "json-server": "^0.16.1"   } } 

Lưu và đóng file . Trong một terminal hoặc tab mới, hãy khởi động server API bằng lệnh sau:

  • npm run api

Tiếp tục chạy phần này trong phần còn lại của hướng dẫn.

Khi bạn chạy lệnh, bạn sẽ nhận được kết quả liệt kê các tài nguyên API:

Output
> json-server db.json -p 3333 \{^_^}/ hi! Loading db.json Done Resources http://localhost:3333/list Home http://localhost:3333 Type s + enter at any time to create a snapshot of the database

Mở http://localhost:3333/list và bạn sẽ tìm thấy API trực tiếp:

Kết quả API, 1

Khi bạn mở một điểm cuối trong trình duyệt của bạn , bạn đang sử dụng phương thức GET . Nhưng json-server không giới hạn ở phương thức GET . Bạn cũng có thể thực hiện nhiều phương pháp REST khác. Ví dụ: bạn có thể POST các mục mới. Trong tab hoặc cửa sổ terminal mới, sử dụng curl để POST một mục mới với loại application/json :

  • curl -d '{"item":"rice"}' -H 'Content-Type: application/json' -X POST http://localhost:3333/list

Lưu ý bạn phải xâu chuỗi nội dung trước khi gửi. Sau khi chạy lệnh curl , bạn sẽ nhận được thông báo thành công:

Output
{ "item": "rice", "id": 3 }

Nếu bạn làm mới trình duyệt, mục mới sẽ xuất hiện:

Nội dung cập nhật, 2

Yêu cầu POST cũng sẽ cập nhật file db.json . Hãy lưu ý đến những thay đổi, vì không có rào cản nào đối với việc vô tình lưu nội dung không có cấu trúc hoặc không hữu ích khi bạn làm việc trên ứng dụng của bạn . Đảm bảo kiểm tra bất kỳ thay đổi nào trước khi chuyển sang kiểm soát version .

Trong bước này, bạn đã tạo một API local . Bạn đã học cách tạo file tĩnh với các giá trị mặc định và cách tìm nạp hoặc cập nhật các giá trị đó bằng cách sử dụng các hành động RESTful như GETPOST . Trong bước tiếp theo, bạn sẽ tạo các dịch vụ để tìm nạp dữ liệu từ API và hiển thị trong ứng dụng của bạn .

Bước 2 - Tìm nạp dữ liệu từ API với useEffect

Trong bước này, bạn sẽ tìm nạp một danh sách các cửa hàng tạp hóa bằng cách sử dụng useEffect Hook. Bạn sẽ tạo một dịch vụ để sử dụng các API trong các folder riêng biệt và gọi dịch vụ đó trong các thành phần React của bạn . Sau khi bạn gọi dịch vụ, bạn sẽ lưu dữ liệu bằng useState Hook và hiển thị kết quả trong thành phần của bạn.

Đến cuối bước này, bạn có thể gọi các API web bằng phương thức Tìm nạpuseEffect Hook. Bạn cũng sẽ có thể lưu và hiển thị kết quả.

Đến đây bạn đã có một API hoạt động, bạn cần một dịch vụ để tìm nạp dữ liệu và các thành phần để hiển thị thông tin. Bắt đầu bằng cách tạo một dịch vụ. Bạn có thể tìm nạp dữ liệu trực tiếp bên trong bất kỳ thành phần React nào, nhưng các dự án của bạn sẽ dễ dàng duyệt và cập nhật hơn nếu bạn giữ các chức năng truy xuất dữ liệu tách biệt với các thành phần hiển thị của bạn . Điều này sẽ cho phép bạn sử dụng lại các phương thức trên các thành phần, mô phỏng trong các bài kiểm tra và cập nhật URL khi điểm cuối thay đổi.

Tạo một folder được gọi là services bên trong folder src :

  • mkdir src/services

Sau đó, mở một file có tên list.js trong editor của bạn:

  • nano src/services/list.js

Bạn sẽ sử dụng file này cho bất kỳ hành động nào trên điểm cuối /list . Thêm một hàm để truy xuất dữ liệu bằng cách sử dụng hàm fetch :

api-tutorial / src / services / list
export function getList() {   return fetch('http://localhost:3333/list')     .then(data => data.json()) } 

Mục tiêu duy nhất của hàm này là truy cập dữ liệu và chuyển đổi phản hồi thành JSON bằng phương thức data.json() . GET là hành động mặc định, vì vậy bạn không cần bất kỳ tham số nào khác.

Ngoài fetch , có những thư viện phổ biến khác như Axios có thể cung cấp cho bạn giao diện trực quan và sẽ cho phép bạn thêm tiêu đề mặc định hoặc thực hiện các hành động khác trên dịch vụ. Nhưng fetch sẽ hoạt động cho hầu hết các yêu cầu.

Lưu và đóng file . Tiếp theo, mở App.css và thêm một số kiểu dáng tối thiểu:

  • nano src/components/App/App.css

Thêm một lớp wrapper với một lượng nhỏ đệm bằng cách thay thế CSS bằng như sau:

api-tutorial / src / components / App / App.css
.wrapper {     padding: 15px; } 

Lưu và đóng file . Đến đây bạn cần thêm mã để truy xuất dữ liệu và hiển thị nó trong ứng dụng của bạn .

Mở App.js :

  • nano src/components/App/App.js

Trong các thành phần chức năng, bạn sử dụng useEffect Hook để tìm nạp dữ liệu khi thành phần tải hoặc một số thông tin thay đổi. Để biết thêm thông tin về việc sử useEffect Hook, hãy xem Cách xử lý khi tải dữ liệu không đồng bộ, tải useEffect và tách mã bằng React . Bạn cũng cần lưu kết quả với useState Hook.

Nhập useEffectuseState , sau đó tạo một biến có tên là list và một setter được gọi là setList để giữ dữ liệu bạn tìm nạp từ dịch vụ bằng useState Hook:

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css';  function App() {   const [list, setList] = useState([]);   return(     <>     </>   ) }  export default App; 

Tiếp theo, nhập dịch vụ, sau đó gọi dịch vụ bên trong useEffect Hook của bạn. Cập nhật list với setList nếu thành phần được mount . Để hiểu lý do tại sao bạn nên kiểm tra xem thành phần có được mount hay không trước khi cài đặt dữ liệu, hãy xem Bước 2 - Ngăn ngừa lỗi trên các thành phần chưa được mount trong Cách xử lý tính năng tải dữ liệu không đồng bộ, tải chậm và phân tách mã bằng React .

Hiện tại, bạn chỉ chạy hiệu ứng một lần khi tải trang, vì vậy mảng phụ thuộc sẽ trống. Trong bước tiếp theo, bạn sẽ kích hoạt hiệu ứng dựa trên các hành động trên trang khác nhau đảm bảo rằng bạn luôn có thông tin cập nhật nhất.

Thêm mã được đánh dấu sau:

api-tutorial / src / components / App / App.js
 import React, { useEffect, useState } from 'react'; import './App.css'; import { getList } from '../../services/list';  function App() {   const [list, setList] = useState([]);    useEffect(() => {    let mounted = true;    getList()      .then(items => {        if(mounted) {          setList(items)        }      })    return () => mounted = false;  }, [])    return(     <>     </>   ) }  export default App; 

Cuối cùng, lặp lại các mục bằng .map và hiển thị chúng trong danh sách:

api-tutorial / src / components / App / App
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList } from '../../services/list';  function App() {   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [])    return(     <div className="wrapper">      <h1>My Grocery List</h1>      <ul>        {list.map(item => <li key={item.item}>{item.item}</li>)}      </ul>    </div>   ) }  export default App; 

Lưu và đóng file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ tìm thấy danh sách các mục:

Liệt kê các mục, 3

Trong bước này, bạn cài đặt một dịch vụ để lấy dữ liệu từ một API. Bạn đã học cách gọi dịch vụ bằng useEffect Hook và cách đặt dữ liệu trên trang. Bạn cũng hiển thị dữ liệu bên trong JSX của bạn .

Trong bước tiếp theo, bạn sẽ gửi dữ liệu tới API bằng cách sử dụng POST và sử dụng phản hồi để thông báo cho user của bạn rằng một hành động đã thành công.

Bước 3 - Gửi dữ liệu tới API

Trong bước này, bạn sẽ gửi dữ liệu trở lại API bằng cách sử dụng API Tìm nạp và phương thức POST . Bạn sẽ tạo một thành phần sẽ sử dụng biểu mẫu web để gửi dữ liệu với trình xử lý sự kiện onSubmit và sẽ hiển thị thông báo thành công khi hành động hoàn tất.

Khi kết thúc bước này, bạn có thể gửi thông tin tới API và bạn có thể thông báo cho user khi yêu cầu được giải quyết.

Gửi dữ liệu đến một dịch vụ

Bạn có một ứng dụng sẽ hiển thị danh sách các mặt hàng tạp hóa, nhưng nó không phải là một ứng dụng tạp hóa rất hữu ích trừ khi bạn cũng có thể lưu nội dung. Bạn cần tạo một dịch vụ sẽ POST một mục mới lên API.

Mở src/services/list.js :

  • nano src/services/list.js

Bên trong file , hãy thêm một hàm sẽ lấy một item làm đối số và sẽ gửi dữ liệu bằng phương thức POST tới API. Như trước đây, bạn có thể sử dụng API Tìm nạp. Lần này, bạn cần thêm thông tin. Thêm một đối tượng tùy chọn làm đối số thứ hai. Bao gồm phương thức— POST — cùng với tiêu đề để đặt Content-Type thành application/json . Cuối cùng, gửi đối tượng mới trong body . Đảm bảo chuyển đổi đối tượng thành chuỗi bằng JSON.stringify .

Khi bạn nhận được phản hồi, hãy chuyển đổi giá trị thành JSON:

hướng dẫn / src / services / list.js
export function getList() {   return fetch('http://localhost:3333/list')     .then(data => data.json()) }  export function setItem(item) {  return fetch('http://localhost:3333/list', {    method: 'POST',    headers: {      'Content-Type': 'application/json'    },    body: JSON.stringify({ item })  })    .then(data => data.json()) } 

Lưu và đóng file .

Lưu ý: Trong các ứng dụng production , bạn cần thêm xử lý và kiểm tra lỗi. Ví dụ: nếu bạn viết sai chính tả cho điểm cuối, bạn vẫn nhận được phản hồi 404 và phương thức data.json() sẽ trả về một đối tượng trống. Để giải quyết vấn đề, thay vì chuyển đổi phản hồi thành JSON, bạn có thể kiểm tra thuộc tính data.ok Nếu nó là sai, bạn có thể tạo ra một lỗi và sau đó sử dụng phương thức .catch trong thành phần của bạn để hiển thị thông báo lỗi cho user .

Đến đây bạn đã tạo một dịch vụ, bạn cần sử dụng dịch vụ bên trong thành phần của bạn .

Mở App.js :

  • nano src/components/App/App.js

Thêm phần tử form xung quanh inputbutton gửi:

api-tutorial / src / components / App / App.js
 import React, { useEffect, useState } from 'react'; import './App.css'; import { getList } from '../../services/list';  function App() {   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [])    return(     <div className="wrapper">       <h1>My Grocery List</h1>       <ul>         {list.map(item => <li key={item.item}>{item.item}</li>)}       </ul>       <form>        <label>          <p>New Item</p>          <input type="text" />        </label>        <button type="submit">Submit</button>      </form>     </div>   ) }  export default App; 

Đảm bảo bao quanh input bằng một label để biểu mẫu có thể truy cập được bằng trình đọc màn hình. Một phương pháp hay là thêm type="submit" vào button để rõ ràng role của việc gửi biểu mẫu.

Lưu các file . Khi bạn làm như vậy, trình duyệt sẽ làm mới và bạn sẽ tìm thấy biểu mẫu của bạn .

Biểu mẫu danh sách tạp hóa

Tiếp theo, chuyển đổi input thành một thành phần được kiểm soát . Bạn cần một thành phần được kiểm soát để có thể xóa trường sau khi user gửi thành công một mục danh sách mới.

Trước tiên, hãy tạo một trình xử lý trạng thái mới để giữ và đặt thông tin đầu vào bằng useState Hook:

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList } from '../../services/list';  function App() {   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [])    return(     <div className="wrapper">       <h1>My Grocery List</h1>       <ul>         {list.map(item => <li key={item.item}>{item.item}</li>)}       </ul>       <form>         <label>           <p>New Item</p>           <input type="text" onChange={event => setItemInput(event.target.value)} value={itemInput} />         </label>         <button type="submit">Submit</button>       </form>     </div>   ) }  export default App; 

Sau khi tạo các trình xử lý trạng thái, hãy đặt giá trị của input thành itemInput và cập nhật giá trị bằng cách chuyển event.target.value đến hàm setItemInput bằng trình xử lý sự kiện onChange .

Như vậy, user của bạn có thể điền vào biểu mẫu với các mục danh sách mới. Tiếp theo, bạn sẽ kết nối biểu mẫu với dịch vụ của bạn .

Tạo một hàm có tên là handleSubmit . handleSubmit sẽ lấy một sự kiện làm đối số và sẽ gọi event.preventDefault() để ngăn biểu mẫu làm mới trình duyệt.

Nhập setItem từ dịch vụ, sau đó gọi setItem với giá trị itemInput bên trong hàm handleSubmit . Kết nối handleSubmit với biểu mẫu bằng cách chuyển nó tới trình xử lý sự kiện onSubmit :

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [])    const handleSubmit = (e) => {     e.preventDefault();     setItem(itemInput)   };    return(     <div className="wrapper">       <h1>My Grocery List</h1>       <ul>         {list.map(item => <li key={item.item}>{item.item}</li>)}       </ul>       <form onSubmit={handleSubmit}>         <label>           <p>New Item</p>           <input type="text" onChange={event => setItemInput(event.target.value)} value={itemInput} />         </label>         <button type="submit">Submit</button>       </form>     </div>   ) }  export default App; 

Lưu các file . Khi bạn làm như vậy, bạn có thể gửi các giá trị. Lưu ý bạn sẽ nhận được phản hồi thành công trong tab mạng. Nhưng danh sách không cập nhật và đầu vào không rõ ràng.

Gửi thành công, 5

Hiển thị Thông báo Thành công

Luôn luôn là một phương pháp hay để cung cấp cho user một số dấu hiệu cho thấy hành động của họ đã thành công. Nếu không, user có thể thử và gửi lại một giá trị nhiều lần hoặc có thể nghĩ rằng hành động của họ không thành công và sẽ rời khỏi ứng dụng.

Để thực hiện việc này, hãy tạo một biến trạng thái và hàm setter với useState để cho biết có hiển thị cho user một thông báo cảnh báo hay không. Nếu alert là đúng, hãy hiển thị <h2> với thông báo Gửi thành công .

Khi lời hứa setItem giải quyết, hãy xóa đầu vào và đặt thông báo cảnh báo:

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [alert, setAlert] = useState(false);   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [])    const handleSubmit = (e) => {     e.preventDefault();     setItem(itemInput)       .then(() => {         setItemInput('');         setAlert(true);       })   };    return(     <div className="wrapper">       <h1>My Grocery List</h1>       <ul>         {list.map(item => <li key={item.item}>{item.item}</li>)}       </ul>       {alert && <h2> Submit Successful</h2>}       <form onSubmit={handleSubmit}>         <label>           <p>New Item</p>           <input type="text" onChange={event => setItemInput(event.target.value)} value={itemInput} />         </label>         <button type="submit">Submit</button>       </form>     </div>   ) }  export default App; 

Lưu các file . Khi bạn làm như vậy, trang sẽ làm mới và bạn sẽ thấy thông báo thành công sau khi yêu cầu API được giải quyết.

Gửi và nhắn tin, 6

Có nhiều cách tối ưu hóa khác mà bạn có thể thêm vào. Ví dụ: bạn có thể cần vô hiệu hóa đầu vào biểu mẫu khi có một yêu cầu đang hoạt động. Bạn có thể tìm hiểu thêm về cách tắt các phần tử biểu mẫu trong Cách tạo biểu mẫu trong React .

Đến đây bạn đã cảnh báo user rằng kết quả đã thành công, nhưng thông báo cảnh báo không biến mất và danh sách không cập nhật. Để khắc phục điều này, hãy bắt đầu bằng cách ẩn cảnh báo. Trong trường hợp này, bạn muốn ẩn thông tin sau một khoảng thời gian ngắn, chẳng hạn như một giây. Bạn có thể sử dụng hàm setTimeout để gọi setAlert(false) , nhưng bạn cần bao bọc nó trong useEffect đảm bảo rằng nó không chạy trên mọi kết xuất thành phần.

Inside of App.js tạo ra một hiệu ứng mới và chuyển alert đến một loạt các trình kích hoạt. Điều này sẽ làm cho hiệu ứng chạy bất kỳ thay đổi alert nào. Lưu ý điều này sẽ chạy nếu alert thay đổi từ false thành true , nhưng nó cũng sẽ chạy khi alert thay đổi từ true thành false . Vì bạn chỉ muốn ẩn cảnh báo nếu nó được hiển thị, hãy thêm điều kiện bên trong hiệu ứng để chỉ chạy setTimeout nếu alerttrue :

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [alert, setAlert] = useState(false);   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);     ...    useEffect(() => {     if(alert) {       setTimeout(() => {         setAlert(false);       }, 1000)     }   }, [alert])    const handleSubmit = (e) => {     e.preventDefault();     setItem(itemInput)       .then(() => {         setItemInput('');         setAlert(true);       })   };    return(     <div className="wrapper">       ...     </div>   ) }  export default App; 

Chạy hàm setTimeout sau 1000 mili giây đảm bảo user có thời gian đọc thay đổi.

Lưu các file . Đến đây bạn có một hiệu ứng sẽ chạy khi nào alert thay đổi. Nếu có một cảnh báo hoạt động, nó sẽ bắt đầu chức năng thời gian chờ sẽ đóng cảnh báo sau một giây.

Ẩn cảnh báo, 7

Làm mới dữ liệu đã tìm nạp

Đến đây bạn cần một cách để làm mới danh sách dữ liệu cũ. Để thực hiện việc này, bạn có thể thêm trình kích hoạt mới vào useEffect Hook để chạy lại yêu cầu getList . Để đảm bảo bạn có dữ liệu phù hợp nhất, bạn cần một trình kích hoạt sẽ cập nhật bất kỳ lúc nào có thay đổi đối với dữ liệu từ xa. May mắn là bạn có thể sử dụng lại trạng thái alert để kích hoạt một lần làm mới dữ liệu khác vì bạn biết rằng nó sẽ chạy khi nào user cập nhật dữ liệu. Như trước đây, bạn phải lập kế hoạch cho thực tế là hiệu ứng sẽ chạy mỗi khi alert thay đổi kể cả khi thông báo cảnh báo biến mất.

Lần này, hiệu ứng cũng cần tìm nạp dữ liệu khi tải trang. Tạo một điều kiện sẽ thoát khỏi hàm trước khi tìm nạp dữ liệu nếu list.length là true — cho biết bạn đã tìm nạp dữ liệu — và alertfalse biết bạn đã làm mới dữ liệu. Đảm bảo thêm alertlist vào mảng trình kích hoạt:

import React, { useEffect, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [alert, setAlert] = useState(false);   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);    useEffect(() => {     let mounted = true;     if(list.length && !alert) {       return;     }     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [alert, list])    ...    return(     <div className="wrapper">       ...     </div>   ) }  export default App; 

Lưu các file . Khi bạn làm như vậy, dữ liệu sẽ làm mới sau khi bạn gửi một mặt hàng mới:

Làm mới danh sách, 8

Trong trường hợp này, alert không liên quan trực tiếp đến trạng thái list . Tuy nhiên, nó xảy ra cùng lúc với một sự kiện sẽ làm mất hiệu lực của dữ liệu cũ, vì vậy bạn có thể sử dụng nó để làm mới dữ liệu.

Ngăn cập nhật trên các thành phần chưa được mount

Vấn đề cuối cùng bạn cần tính đến là đảm bảo bạn không đặt trạng thái trên một thành phần chưa được mount . Bạn có giải pháp cho vấn đề với let mounted = true trong hiệu ứng của bạn để tìm nạp dữ liệu, nhưng giải pháp sẽ không hoạt động đối với handleSubmit , vì nó không phải là hiệu ứng. Bạn không thể trả về một hàm để đặt giá trị thành false khi nó được ngắt kết nối. Hơn nữa, sẽ không hiệu quả nếu thêm cùng một kiểm tra cho mọi chức năng.

Để giải quyết vấn đề này, bạn có thể tạo một biến chia sẻ được sử dụng bởi nhiều chức năng bằng cách nâng mounted ra khỏi useEffect Hook và giữ nó ở mức của thành phần. Bạn sẽ vẫn sử dụng hàm để đặt giá trị thành false khi kết thúc useEffect .

Bên trong App.js , khai báo mounted vào khi bắt đầu hàm. Sau đó, kiểm tra xem thành phần đã được mount chưa trước khi cài đặt dữ liệu trong các chức năng không đồng bộ khác. Đảm bảo loại bỏ khai báo mounted bên trong hàm useEffect :

api-tutorial / src / components / App / App.js
import React, { useEffect, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [alert, setAlert] = useState(false);   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);   let mounted = true;    useEffect(() => {     if(list.length && !alert) {       return;     }     getList()       .then(items => {         if(mounted) {           setList(items)         }       })     return () => mounted = false;   }, [alert, list])    useEffect(() => {     if(alert) {       setTimeout(() => {         if(mounted) {           setAlert(false);         }       }, 1000)     }   }, [alert])    const handleSubmit = (e) => {     e.preventDefault();     setItem(itemInput)       .then(() => {         if(mounted) {           setItemInput('');           setAlert(true);         }       })   };    return(     <div className="wrapper">       ...     </div>   ) }  export default App; 

Khi bạn thực hiện thay đổi, bạn sẽ nhận được lỗi trong terminal nơi bạn đang chạy ứng dụng React của bạn :

Error
Assignments to the 'mounted' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect react-hooks/exhaustive-deps

React đang cảnh báo bạn rằng các biến không ổn định. Khi nào có kết xuất lại, nó sẽ tính toán lại biến. Thông thường, điều này sẽ đảm bảo thông tin cập nhật. Trong trường hợp này, bạn đang dựa vào biến đó để tồn tại.

Giải pháp là một Hook khác được gọi là useRef . useRef Hook sẽ duy trì một biến trong suốt thời gian tồn tại của thành phần. Bí quyết duy nhất là lấy giá trị bạn cần để sử dụng thuộc tính .current .

Bên trong App.js , chuyển đổi mounted thành tham chiếu bằng useRef Hook. Sau đó, chuyển đổi từng cách sử dụng mounted thành mounted.current :

api-tutorial / src / components / App / App.js
import React, { useEffect, useRef, useState } from 'react'; import './App.css'; import { getList, setItem } from '../../services/list';  function App() {   const [alert, setAlert] = useState(false);   const [itemInput, setItemInput] = useState('');   const [list, setList] = useState([]);   const mounted = useRef(true);    useEffect(() => {     mounted.current = true;     if(list.length && !alert) {       return;     }     getList()       .then(items => {         if(mounted.current) {           setList(items)         }       })     return () => mounted.current = false;   }, [alert, list])    useEffect(() => {     if(alert) {       setTimeout(() => {         if(mounted.current) {           setAlert(false);         }       }, 1000)     }   }, [alert])    const handleSubmit = (e) => {     e.preventDefault();     setItem(itemInput)       .then(() => {         if(mounted.current) {           setItemInput('');           setAlert(true);         }       })   };    return(     <div className="wrapper">        ...     </div>   ) }  export default App; 

Ngoài ra, hãy thận trọng về việc đặt biến trong hàm dọn dẹp để sử useEffect . Chức năng dọn dẹp sẽ luôn chạy trước khi hiệu ứng chạy lại. Điều đó nghĩa là hàm dọn dẹp () => mounted.current = false sẽ chạy mỗi khi alert hoặc list thay đổi. Để tránh bất kỳ kết quả sai nào, hãy đảm bảo cập nhật mounted.current thành true khi bắt đầu hiệu ứng. Sau đó, bạn có thể chắc chắn rằng nó sẽ chỉ được đặt thành false khi thành phần được ngắt kết nối.

Lưu và đóng file . Khi trình duyệt làm mới, bạn có thể lưu các mục danh sách mới:

Đang lưu lại, 9

Lưu ý: Việc vô tình chạy lại một API nhiều lần là một vấn đề phổ biến. Mỗi khi một thành phần bị xóa và sau đó được gắn lại, bạn sẽ chạy lại tất cả quá trình tìm nạp dữ liệu ban đầu. Để tránh điều này, hãy xem xét phương pháp lưu vào bộ nhớ đệm cho các API đặc biệt nặng hoặc chậm. Bạn có thể sử dụng bất cứ thứ gì từ ghi nhớ các cuộc gọi dịch vụ, đến bộ nhớ đệm với nhân viên dịch vụ , cho đến một Hook tùy chỉnh. Có một số Hooks tùy chỉnh phổ biến cho các cuộc gọi dịch vụ bộ nhớ đệm, bao gồm useSWRtruy vấn phản ứng .

Cho dù bạn sử dụng cách tiếp cận nào, hãy chắc chắn xem xét cách bạn sẽ làm mất hiệu lực bộ nhớ cache vì đôi khi bạn cần tìm nạp dữ liệu mới nhất.

Trong bước này, bạn đã gửi dữ liệu đến một API. Bạn đã học cách cập nhật user khi dữ liệu được gửi và cách kích hoạt làm mới dữ liệu danh sách của bạn. Bạn cũng tránh cài đặt dữ liệu trên các thành phần chưa được mount bằng cách sử dụng useRef Hook để lưu trữ trạng thái của thành phần để nó được dùng bởi nhiều dịch vụ.

Kết luận

API cung cấp cho bạn khả năng kết nối với nhiều dịch vụ hữu ích. Chúng cho phép bạn lưu trữ và truy xuất dữ liệu ngay cả sau khi user đóng trình duyệt của họ hoặc ngừng sử dụng ứng dụng. Với mã được tổ chức tốt, bạn có thể cô lập các dịch vụ của bạn khỏi các thành phần của bạn để các thành phần của bạn có thể tập trung vào việc hiển thị dữ liệu mà không cần biết dữ liệu bắt nguồn từ đâu. API Web mở rộng ứng dụng của bạn vượt xa khả năng của phiên trình duyệt hoặc bộ nhớ. Họ mở ứng dụng của bạn cho toàn bộ thế giới công nghệ web.

Nếu bạn muốn đọc thêm các hướng dẫn về React, hãy xem trang Chủ đề React của ta hoặc quay lại trang Cách viết mã trong chuỗi React.js .


Tags:

Các tin liên quan

Cách triển khai xác thực API bằng mã thông báo web JSON và hộ chiếu
2020-09-24
Cách cài đặt và sử dụng GoAccess Web Log Analyzer trên Ubuntu 20.04
2020-09-15
Xây dựng ứng dụng web CRUD với Python và Flask - Phần thứ nhất
2020-09-15
Phông chữ có thể thay đổi trên web bằng CSS
2020-09-01
Làm thế nào để tạo một Web Scraper đồng thời với Puppeteer, Node.js, Docker và Kubernetes
2020-08-19
Cách tạo ứng dụng web tiến bộ với Angular
2020-07-09
Cách cài đặt Django Web Framework trên Ubuntu 20.04
2020-07-06
Cách tạo chế độ xem để phát triển web Django
2020-05-14
Cách tạo chế độ xem để phát triển web Django
2020-05-14
Cách tạo ứng dụng web bằng Flask trong Python 3
2020-04-16