Có nhiều cách để làm cho các thành phần giao tiếp. Một số có thể phù hợp với usecase của bạn. Dưới đây là danh sách một số tôi thấy hữu ích để biết.
Phản ứng
Giao tiếp trực tiếp giữa phụ huynh / trẻ em
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
Ở đây, thành phần con sẽ gọi một cuộc gọi lại được cung cấp bởi cha mẹ với một giá trị và cha mẹ sẽ có thể nhận được giá trị được cung cấp bởi con cái trong cha mẹ.
Nếu bạn xây dựng một tính năng / trang của ứng dụng của bạn, nó tốt hơn để có một người mẹ độc thân quản lý callbacks / nhà nước (còn gọi là container
hay smart component
), và tất cả Childs được không quốc tịch, chỉ có báo cáo điều cần phụ huynh. Bằng cách này, bạn có thể dễ dàng "chia sẻ" trạng thái của cha mẹ cho bất kỳ đứa trẻ nào cần nó.
Bối cảnh
React Context cho phép giữ trạng thái ở gốc của hệ thống phân cấp thành phần của bạn và có thể dễ dàng đưa trạng thái này vào các thành phần được lồng rất sâu, mà không gặp rắc rối khi phải truyền đạo cụ cho mọi thành phần trung gian.
Cho đến hiện tại, bối cảnh là một tính năng thử nghiệm, nhưng API mới có sẵn trong React 16.3.
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
Người tiêu dùng đang sử dụng mẫu chức năng render prop / children
Kiểm tra bài đăng trên blog này để biết thêm chi tiết.
Trước React 16.3, tôi khuyên bạn nên sử dụng phản ứng phát sóng cung cấp API khá giống nhau và sử dụng API ngữ cảnh cũ.
Cổng thông tin
Sử dụng cổng thông tin khi bạn muốn giữ 2 thành phần gần nhau để khiến chúng giao tiếp với các chức năng đơn giản, như trong cha mẹ / con bình thường, nhưng bạn không muốn 2 thành phần này có mối quan hệ cha / con trong DOM, bởi vì các ràng buộc trực quan / CSS mà nó ngụ ý (như z-index, opacity ...).
Trong trường hợp này, bạn có thể sử dụng một "cổng thông tin". Có khác nhau phản ứng thư viện sử dụng cổng thông tin , thường được sử dụng cho modals , quảng cáo, tooltips ...
Hãy xem xét những điều sau đây:
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
Có thể tạo DOM sau khi được hiển thị bên trong reactAppContainer
:
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
Thêm chi tiết tại đây
Máy đánh bạc
Bạn xác định một vị trí ở đâu đó và sau đó bạn điền vào vị trí đó từ một nơi khác trong cây kết xuất của bạn.
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
Điều này hơi giống với các cổng ngoại trừ nội dung được điền sẽ được hiển thị trong một vị trí bạn xác định, trong khi các cổng thường hiển thị một nút dom mới (thường là con của document.body)
Kiểm tra thư viện phản ứng-slot-fill
Xe buýt sự kiện
Như đã nêu trong tài liệu React :
Để liên lạc giữa hai thành phần không có mối quan hệ cha-con, bạn có thể thiết lập hệ thống sự kiện toàn cầu của riêng mình. Theo dõi các sự kiện trong thành phầnDidMount (), hủy đăng ký thành phầnWillUnmount () và gọi setState () khi bạn nhận được một sự kiện.
Có nhiều thứ bạn có thể sử dụng để thiết lập một xe buýt sự kiện. Bạn chỉ có thể tạo một mảng người nghe và trên xuất bản sự kiện, tất cả người nghe sẽ nhận được sự kiện. Hoặc bạn có thể sử dụng một cái gì đó như EventEuctor hoặc PostalJs
Tuôn ra
Flux về cơ bản là một xe buýt sự kiện, ngoại trừ người nhận sự kiện là các cửa hàng. Điều này tương tự như hệ thống xe buýt sự kiện cơ bản ngoại trừ trạng thái được quản lý bên ngoài React
Việc triển khai Flux ban đầu trông giống như một nỗ lực để thực hiện tìm nguồn cung ứng Sự kiện theo cách hacky.
Redux đối với tôi là triển khai Flux gần nhất với nguồn cung cấp sự kiện, một lợi ích của nhiều lợi thế tìm nguồn cung ứng sự kiện như khả năng du hành thời gian. Nó không được liên kết chặt chẽ với React và cũng có thể được sử dụng với các thư viện xem chức năng khác.
Video hướng dẫn Redux của Egghead thực sự rất hay và giải thích cách thức hoạt động bên trong (nó thực sự đơn giản).
Con trỏ
Các con trỏ đến từ ClojureScript / Om và được sử dụng rộng rãi trong các dự án React. Chúng cho phép quản lý trạng thái bên ngoài React và để nhiều thành phần có quyền truy cập đọc / ghi vào cùng một phần của trạng thái mà không cần biết gì về cây thành phần.
Nhiều triển khai tồn tại, bao gồm ImmutableJS , React-cursors và Omniscient
Chỉnh sửa 2016 : có vẻ như mọi người đồng ý rằng con trỏ hoạt động tốt cho các ứng dụng nhỏ hơn nhưng nó không mở rộng tốt trên các ứng dụng phức tạp. Om Next không còn con trỏ nữa (trong khi đó Om đã giới thiệu khái niệm ban đầu)
Kiến trúc Elm
Các kiến trúc Elm là một kiến trúc được đề nghị sử dụng bởi các ngôn ngữ Elm . Ngay cả khi Elm không phải là ReactJS, kiến trúc Elm cũng có thể được thực hiện trong React.
Dan Abramov, tác giả của Redux, đã thực hiện kiến trúc Elm bằng React.
Cả Redux và Elm đều thực sự tuyệt vời và có xu hướng trao quyền cho các khái niệm tìm nguồn cung ứng sự kiện trên frontend, cả hai đều cho phép gỡ lỗi du hành thời gian, hoàn tác / làm lại, phát lại ...
Sự khác biệt chính giữa Redux và Elm là Elm có xu hướng nghiêm ngặt hơn rất nhiều về quản lý nhà nước. Trong Elm, bạn không thể có trạng thái thành phần cục bộ hoặc móc nối / ngắt kết nối và tất cả các thay đổi DOM phải được kích hoạt bởi các thay đổi trạng thái toàn cầu. Kiến trúc Elm đề xuất một cách tiếp cận có thể mở rộng cho phép xử lý TẤT CẢ trạng thái bên trong một đối tượng bất biến duy nhất, trong khi Redux đề xuất một phương pháp mời bạn xử lý MOST của trạng thái trong một đối tượng bất biến duy nhất.
Mặc dù mô hình khái niệm của Elm rất thanh lịch và kiến trúc cho phép mở rộng tốt trên các ứng dụng lớn, nhưng thực tế nó có thể khó khăn hoặc liên quan đến nhiều nồi hơi hơn để đạt được các nhiệm vụ đơn giản như tập trung vào đầu vào sau khi cài đặt hoặc tích hợp với thư viện hiện có với giao diện bắt buộc (tức là plugin JQuery). Vấn đề liên quan .
Ngoài ra, kiến trúc Elm liên quan đến nhiều mẫu mã hơn. Nó không dài dòng hay phức tạp để viết nhưng tôi nghĩ kiến trúc Elm phù hợp hơn với các ngôn ngữ gõ tĩnh.
FRP
Các thư viện như RxJS, BaconJS hoặc Kefir có thể được sử dụng để tạo ra các luồng FRP để xử lý giao tiếp giữa các thành phần.
Bạn có thể thử ví dụ Rx-React
Tôi nghĩ rằng việc sử dụng các lib này khá giống với việc sử dụng những gì mà ngôn ngữ ELM cung cấp với các tín hiệu .
Khung Chu trình không sử dụng ReactJS mà sử dụng vdom . Nó có nhiều điểm tương đồng với kiến trúc Elm (nhưng dễ sử dụng hơn trong cuộc sống thực vì nó cho phép móc vdom) và nó sử dụng RxJ rộng rãi thay vì các chức năng và có thể là nguồn cảm hứng tốt nếu bạn muốn sử dụng FRP với Phản ứng. Các video của EgJead Egghead rất hay để hiểu cách thức hoạt động của nó.
CSP
CSP (Giao tiếp quy trình tuần tự) hiện đang phổ biến (chủ yếu là do Go / goroutines và core.async / ClojureScript) nhưng bạn cũng có thể sử dụng chúng trong javascript với JS-CSP .
James Long đã thực hiện một video giải thích làm thế nào nó có thể được sử dụng với React.
Sagas
Một saga là một khái niệm phụ trợ xuất phát từ thế giới DDD / EventSource / CQRS, còn được gọi là "trình quản lý quy trình". Nó đang được phổ biến bởi dự án redux-saga , chủ yếu là thay thế cho redux-thunk để xử lý các hiệu ứng phụ (ví dụ như các lệnh gọi API, v.v.). Hầu hết mọi người hiện nay nghĩ rằng nó chỉ phục vụ cho các tác dụng phụ nhưng thực sự là về các thành phần tách rời.
Nó giống như một lời khen cho kiến trúc Flux (hoặc Redux) hơn là một hệ thống giao tiếp hoàn toàn mới, bởi vì saga phát ra các hành động Flux ở cuối. Ý tưởng là nếu bạn có widget1 và widget2 và bạn muốn tách chúng ra, bạn không thể thực hiện hành động nhắm mục tiêu widget2 từ widget1. Vì vậy, bạn tạo widget1 chỉ bắn các hành động nhắm mục tiêu vào chính nó và saga là một "quá trình nền" lắng nghe các hành động của widget1 và có thể gửi các hành động nhắm đến widget2. Saga là điểm kết nối giữa 2 widget nhưng các widget vẫn tách rời.
Nếu bạn quan tâm hãy xem câu trả lời của tôi ở đây
Phần kết luận
Nếu bạn muốn xem một ví dụ về cùng một ứng dụng nhỏ sử dụng các kiểu khác nhau này, hãy kiểm tra các nhánh của kho lưu trữ này .
Tôi không biết đâu là lựa chọn tốt nhất trong dài hạn nhưng tôi thực sự thích cách Flux trông giống như tìm nguồn cung ứng sự kiện.
Nếu bạn không biết các khái niệm tìm nguồn cung ứng sự kiện, hãy xem blog rất sư phạm này: Biến cơ sở dữ liệu ra ngoài với apache Samza , đây là điều cần phải đọc để hiểu tại sao Flux lại tốt (nhưng điều này cũng có thể áp dụng cho FRP )
Tôi nghĩ rằng cộng đồng đồng ý rằng việc triển khai Flux hứa hẹn nhất là Redux , điều này sẽ dần dần cho phép trải nghiệm rất hiệu quả của nhà phát triển nhờ tải lại nóng. Có thể tạo video ấn tượng ala Bret Victor's Inventing on Princuctor video !