Menggunakan children
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = ({name}) => (
<Wrapper>
<App name={name}/>
</Wrapper>
);
render(<WrappedApp name="toto"/>,node);
Ini juga dikenal sebagai transclusion
di Angular.
children
adalah prop khusus di Bereaksi dan akan berisi apa yang ada di dalam tag komponen Anda (di sini <App name={name}/>
ada di dalam Wrapper
, jadi itu adalahchildren
Perhatikan bahwa Anda tidak perlu menggunakan children
, yang unik untuk komponen, dan Anda juga dapat menggunakan alat peraga normal jika Anda mau, atau mencampur alat peraga dan anak-anak:
const AppLayout = ({header,footer,children}) => (
<div className="app">
<div className="header">{header}</div>
<div className="body">{children}</div>
<div className="footer">{footer}</div>
</div>
);
const appElement = (
<AppLayout
header={<div>header</div>}
footer={<div>footer</div>}
>
<div>body</div>
</AppLayout>
);
render(appElement,node);
Ini sederhana dan bagus untuk banyak usecases, dan saya akan merekomendasikan ini untuk sebagian besar aplikasi konsumen.
render alat peraga
Dimungkinkan untuk meneruskan fungsi render ke komponen, pola ini umumnya disebut render prop
, danchildren
penyangga sering digunakan untuk menyediakan panggilan balik itu.
Pola ini tidak dimaksudkan untuk tata letak. Komponen pembungkus umumnya digunakan untuk menahan dan mengelola beberapa keadaan dan menyuntikkannya dalam fungsi render-nya.
Contoh penghitung:
const Counter = () => (
<State initial={0}>
{(val, set) => (
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
)}
</State>
);
Anda bisa menjadi lebih mewah dan bahkan menyediakan objek
<Promise promise={somePromise}>
{{
loading: () => <div>...</div>,
success: (data) => <div>{data.something}</div>,
error: (e) => <div>{e.message}</div>,
}}
</Promise>
Perhatikan bahwa Anda tidak perlu menggunakannya children
, ini adalah masalah selera / API.
<Promise
promise={somePromise}
renderLoading={() => <div>...</div>}
renderSuccess={(data) => <div>{data.something}</div>}
renderError={(e) => <div>{e.message}</div>}
/>
Sampai hari ini, banyak perpustakaan menggunakan render props (React context, React-motion, Apollo ...) karena orang cenderung menemukan API ini lebih mudah daripada HOC. react-powerplug adalah kumpulan komponen render-prop sederhana. Reaksi-adopsi membantu Anda melakukan komposisi.
Komponen Tingkat Tinggi (HOC).
const wrapHOC = (WrappedComponent) => {
class Wrapper extends React.PureComponent {
render() {
return (
<div>
<div>header</div>
<div><WrappedComponent {...this.props}/></div>
<div>footer</div>
</div>
);
}
}
return Wrapper;
}
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = wrapHOC(App);
render(<WrappedApp name="toto"/>,node);
Sebuah Tingkat Tinggi Komponen / HOC umumnya merupakan fungsi yang mengambil komponen dan mengembalikan komponen baru.
Menggunakan Komponen Orde Tinggi dapat lebih berkinerja daripada menggunakan children
atau render props
, karena pembungkus dapat memiliki kemampuan untuk hubungan pendek rendering selangkah lebih maju dengan shouldComponentUpdate
.
Di sini kita gunakan PureComponent
. Saat merender ulang aplikasi, jika WrappedApp
prop nama tidak berubah dari waktu ke waktu, pembungkusnya memiliki kemampuan untuk mengatakan "Saya tidak perlu merender karena props (sebenarnya, nama) sama seperti sebelumnya". Dengan children
solusi berbasis di atas, bahkan jika pembungkusnya PureComponent
, itu tidak terjadi karena elemen anak-anak diciptakan kembali setiap kali orangtua membuat, yang berarti pembungkus kemungkinan akan selalu merender ulang, bahkan jika komponen yang dibungkus adalah murni. Ada plugin babel yang dapat membantu mengurangi ini dan memastikan children
elemen konstan dari waktu ke waktu.
Kesimpulan
Komponen Tingkat Tinggi dapat memberi Anda kinerja yang lebih baik. Ini tidak terlalu rumit tetapi pada awalnya terlihat tidak ramah.
Jangan bermigrasi seluruh basis kode Anda ke HOC setelah membaca ini. Ingatlah bahwa pada jalur kritis aplikasi Anda, Anda mungkin ingin menggunakan HOC alih-alih pembungkus runtime karena alasan kinerja, terutama jika pembungkus yang sama digunakan berkali-kali, ada baiknya mempertimbangkan menjadikannya HOC.
Redux pada awalnya menggunakan pembungkus runtime <Connect>
dan kemudian beralih ke HOC connect(options)(Comp)
karena alasan kinerja (secara default, pembungkus itu murni dan digunakan shouldComponentUpdate
). Ini adalah ilustrasi sempurna dari apa yang ingin saya soroti dalam jawaban ini.
Catatan jika suatu komponen memiliki API render-prop, umumnya mudah untuk membuat HOC di atasnya, jadi jika Anda seorang penulis lib, Anda harus menulis API render prop terlebih dahulu, dan akhirnya menawarkan versi HOC. Inilah yang Apollo lakukan dengan <Query>
komponen render-prop, dan graphql
HOC menggunakannya.
Secara pribadi, saya menggunakan keduanya, tetapi ketika ragu saya lebih suka HOC karena:
- Lebih idiomatik untuk membuat mereka (
compose(hoc1,hoc2)(Comp)
) dibandingkan dengan membuat alat peraga
- Itu bisa memberi saya penampilan yang lebih baik
- Saya akrab dengan gaya pemrograman ini
Saya tidak ragu menggunakan / membuat versi HOC dari alat favorit saya:
- React's
Context.Consumer
comp
- Tidak dinyatakan
Subscribe
- menggunakan
graphql
HOC dari Apollo sebagai ganti Query
render prop
Menurut pendapat saya, kadang-kadang membuat alat peraga membuat kode lebih mudah dibaca, kadang-kadang kurang ... Saya mencoba menggunakan solusi yang paling pragmatis sesuai dengan kendala yang saya miliki. Terkadang keterbacaan lebih penting daripada penampilan, kadang tidak. Pilih dengan bijak dan jangan ikuti tren 2018 untuk mengubah segalanya menjadi render-props.