Redux: wadah vs komponen?

Dibuat pada 19 Sep 2015  ·  46Komentar  ·  Sumber: reduxjs/redux

Dalam contoh, selalu ada folder bernama "container" dan folder bernama "component". Apa pemikiran di balik pemisahan ini?

Apakah "container" merupakan komponen pintar atau apakah mereka merutekan komponen atau sesuatu yang lain? Haruskah komponen di bawah "komponen" selalu bodoh?

docs question

Komentar yang paling membantu

Saya menyebut components encapsulated React komponen yang hanya digerakkan oleh props dan tidak berbicara dengan Redux. Sama seperti "komponen bodoh". Mereka harus tetap sama terlepas dari router Anda, pustaka pengambilan data, dll.

Saya menyebut containers Bereaksi komponen yang mengetahui Redux, Router, dll. Mereka lebih digabungkan ke aplikasi. Sama seperti "komponen pintar".

Semua 46 komentar

Bagi saya, container adalah pengendali rute, yang juga menarik status redux untuk rute itu. Kemudian saya menurunkan status saya sebagai penyangga.

Sebagai contoh,

container / properties.jsx

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect }  from 'react-redux';

import * as actions from 'actions/properties';
import Filter from 'components/properties/filter';
import List from 'components/properties/list';
import Pagination from 'components/properties/pagination';

class PropertiesContainer extends Component {
  render() {
    return (
      <section>
        <Filter filter={this.props.properties.params.filter} />
        <List items={this.props.properties.items} isFetching={this.props.properties.isFetching} />
        <Pagination pagination={this.props.properties.params.pagination} />
      </section>
    );
  }
}

function mapState(state) {
  const { properties } = state;

  return { properties };
}

function mapDispatch(dispatch) {
  return {
    actions: bindActionCreators(actions, dispatch),
  };
}

const Connector = connect(mapState, mapDispatch)(PropertiesContainer);

export default Connector;

dan, misalnya,

komponen / properti / pagination.jsx

import React, { Component } from 'react';
import Pager from 'components/ui/pager';

class Pagination extends Component {
  render() {
    const { total, offset, limit } = this.props.pagination;
    const current = offset / limit;

    return (
      <Pager total={total} current={current} />
    )
  }
}

export default Pagination;

Membaca dari tautan yang Anda berikan:

"A container does data fetching and then renders its corresponding sub-component. "

Saya mendapatkan lebih banyak perasaan bahwa "kontainer" sebenarnya adalah apa yang di redux disebut "komponen pintar" ... dan rute / halaman harus mendapatkan foldernya sendiri.

Saya tidak yakin mengapa "container" dan "route handlers" berhubungan dengan cara apa pun?

Mengelompokkan komponen aplikasi Anda berdasarkan rute merupakan praktik yang sangat umum. Seperti yang ditunjukkan @theaqua , juga umum untuk membuat setiap penangan rute / komponen menjadi komponen / wadah pintar. Jika Anda menggunakan CombinedReducers, Anda akan sering menemukan diri Anda memecah status, rute, dan penampung di sepanjang jalur yang sama. Makanya, mereka sering bergaul bersama.

@ronag Saya tidak berpikir Anda perlu membuat wadah dan halaman. Mengapa Anda tidak dapat menempatkan penangan rute & konektor redux ke status di 1 tempat? Ini sangat berguna. Jaga agar tetap sederhana.

Dalam aplikasi saya, saya hanya memiliki 3 rute / halaman. Di sisi lain, saya memiliki banyak panel / modul independen. Menghasilkan connect yang besar tidak mungkin. Setidaknya saya harus membaginya dalam beberapa panel.

Jika saya melakukan semua pemetaan dari negara bagian ke alat peraga dan semua pengambilan data dalam satu file, itu tidak akan dapat dipertahankan. Apalagi jika saya melakukan semua pengambilan data di lokasi yang sama.

Jika Anda memiliki 3 rute, maka Anda membutuhkan 3 penangan rute. Misalnya, A.jsx , B.jsx dan C.jsx di /containers .

Di setiap penampung Anda menarik sebagian (bukan keseluruhan!) Dari status redux dan tindakan mengikat. Kemudian Anda meneruskan ini ke komponen seperti dalam contoh saya. Ini sangat mudah dipelihara, karena saya (dan tim saya) tahu - terhubung ke redux dan tindakan mengikat selalu dalam containers , tidak akan pernah dalam components (yang kecil dan sering tanpa kewarganegaraan seperti dalam contoh saya ).

Saya rasa saya mengerti saran Anda. Namun, seperti yang saya katakan, 3 file tersebut akan menjadi sangat rumit jika saya meletakkan semua data saya saat mengambilnya di sana. Dalam tujuan kami, itu pada dasarnya akan menjadi "Masuk, Aplikasi, Keluar" di mana Aplikasi akan berisi hampir semuanya.

Mungkin saya terlalu bias pada Relay mana setiap komponen memiliki wadah yang menjelaskan data apa yang akan diambil dan bagaimana tampilannya.

Saya akan mencoba saran Anda dan melihat di mana kita berakhir.

Saya menyebut components encapsulated React komponen yang hanya digerakkan oleh props dan tidak berbicara dengan Redux. Sama seperti "komponen bodoh". Mereka harus tetap sama terlepas dari router Anda, pustaka pengambilan data, dll.

Saya menyebut containers Bereaksi komponen yang mengetahui Redux, Router, dll. Mereka lebih digabungkan ke aplikasi. Sama seperti "komponen pintar".

@gaearon : Sempurna. Itu memperjelas contoh. Terima kasih.

@gaearon Jadi "dumb components" adalah komponen stateless, yang dapat ditulis dalam sintaks yang lebih sederhana Sejak React 0.14 , misalnya:

var Aquarium = (props) => {
  var fish = getFish(props.species);
  return <Tank>{fish}</Tank>;
};

Apakah saya benar?

@souline ya.

Belum tentu. Sintaks bukanlah intinya.

Komponen "bodoh" alias "presentasi" adalah komponen yang menerima semua data dengan props, tidak mengetahui Redux, dan hanya menentukan tampilan tetapi tidak perilakunya.

@theaqua @gaearon Terima kasih!

Meskipun istilah "wadah" sudah cukup populer di nomenklatur react / redux, kami memutuskan untuk menyebutnya "konektor" dalam proyek yang saya kerjakan, untuk menghindari kebingungan dengan layout / wadah grafis.

btw, cara memanggilnya telah dibahas sebelumnya di sini rackt / react-redux # 170. Saya menyimpan semuanya di dalam folder components dan yang presentasi satu tingkat lebih dalam, di dalam components/presentational , dan menurut saya tidak apa-apa karena tidak mungkin dibutuhkan oleh bagian aplikasi selain kontainer.

@gaearon jadi apakah komponen yang dispatch dianggap "bodoh" atau "pintar"? Sangat berguna untuk memiliki daun atau komponen perantara untuk mengirimkan tindakan alih-alih membuat peristiwa menggelembung kembali ke komponen atas untuk melakukan pengiriman.

Ya itu kadang-kadang bisa berguna meskipun saya lebih suka connect() komponen seperti itu sehingga pembuat tindakan disuntikkan sebagai penyangga. Tidak masalah bagaimana Anda menyebutnya :-)

Bagaimana saat Anda membangun modul komponen? Misalnya, saya memiliki modul node terpisah untuk menu navigasi <NavMenu> Saya ingin orang melakukan kode seperti ini:

import {NavMenu} from 'my-redux-aware-components';

export function myPage(props) {
  return (<div><NavMenu routes={props.routes} /></div>);
}

jadi apakah saya hanya menamainya 'NavMenuContainer'? itu tampak aneh bagiku. Haruskah saya menamai komponen NavMenuComponent? keduanya tampak aneh bagiku. Dalam hal ini komponen hanya memanggil sambungkan untuk mendapatkan 1 bidang dari status. Apakah seburuk itu sebaris panggilan untuk terhubung seperti ini?

export default const NavMenu = connect(state => ({currentPath:state.routing.path})(React.createClas({...}));

Penasaran untuk mendengar pendapat Anda @gaearon tentang kapan (jika ada) "oke" untuk hanya sebaris panggilan terhubung ...

Tidak peduli bagaimana Anda menyebutnya. Mengapa tidak menyebutnya NavMenu ?

Saya tidak mengerti pertanyaan tentang sebaris.
Akan membantu jika Anda mempresentasikan dua pendekatan yang Anda bandingkan.

ok jadi contohnya.
opsi 1 (2 file terpisah, 1 untuk penampung, 1 untuk komponen)

kontainer / NavMenu

import {connect} from 'react-redux';
import NavMenu from '../components/NavMenu';

export default connect(state => ({currentPath:state.routing.path})(NavMenu);

opsi 2 (1 file tunggal berisi keduanya):
komponen / NavMenu

import {connect} from 'react-redux';

export default connect(state => ({currentPath:state.routing.path})(React.createClass({
  render() {
      return <div>the menu {this.props.currentPath} goes here</div>;
  }
});

yang saya maksud dengan menyebariskan hanyalah memiliki satu file (sebagai lawan dari 2 file) yang merupakan wadah dan komponen karena hanya ada 1 sedikit tentang currentPath yang diperlukan dari status. Apakah ini hanya sesuatu yang harus selalu dihindari atau masuk akal untuk dilakukan dalam kasus sederhana seperti ini?

Tentu, masuk akal untuk melakukan ini dalam kasus sederhana.

OK keren. kapan Anda akan menarik garis dan berkata "oke, saya akan memindahkan ini ke dalam 2 file terpisah"?

Ketika komponen mulai mencampur masalah data (bagaimana mengambil / menghitung data, bagaimana mengirimkan tindakan) dengan presentasi (bagaimana tampilannya). Ketika menjadi sulit untuk menguji atau menggunakan kembali dalam konteks yang berbeda.

@benmon Satu pemikiran lagi. Jika Anda membuat modul komponen, terkadang Anda ingin menghubungkan komponen ini ke berbagai bagian pohon status aplikasi Anda, atau menguji presentasinya secara terpisah dengan berbagai status. Dalam kasus ini, memiliki connect di dalam modul komponen ini akan membatasi kemampuan ini.

terima kasih @gaearon

@sompylasar poin yang sangat bagus! Terima kasih

hmm ok setelah melalui kode saya untuk refactor itu untuk membaginya, sekarang saya memiliki pertanyaan tindak lanjut. misalkan saya juga memiliki wadah <NavMenuItem> . Komponen <NavMenu> perlu mereferensikan <NavMenuItem /> sebagai elemen anak. Haruskah saya melakukan import NavMenuItem from '../containers/NavMenuItem' di komponen NavMenu? Bagaimana hal ini memengaruhi testabilitas @sompylasar?

Saya akan menjadikan NavMenuItem sebagai komponen presentasi murni dengan semua data yang dibutuhkan diteruskan ke dalamnya melalui props oleh NavMenu. Ini akan memungkinkan untuk mengujinya secara terpisah. Jadi, Anda akan memiliki dua komponen presentasional (NavMenu, NavMenuItem) dan satu terhubung (connect (...) (NavMenuItem)).

Satu hal yang saya lewatkan dalam diskusi ini: Jika Anda memilikinya dalam satu file, Anda tidak dapat menggunakan rendering dangkal untuk pengujian. Saya telah melihat orang-orang mengekspos komponen presentasi dan komponen kontainer untuk mengatasi hal ini, dan mengujinya secara terpisah, jadi dalam kasus ini saya lebih suka memiliki dua file untuk membuatnya eksplisit bahwa ini adalah dua hal. Ini juga menyoroti pemisahan perhatian di sini dan fakta bahwa komponen presentasi adalah independen dan dapat digunakan kembali.

FWIW Saya memperbarui artikel Presentational and Container Components untuk mencerminkan pemikiran saya saat ini.

Kami tidak lagi melarang pembuatan komponen kontainer di dokumen yang diperbarui.
http://redux.js.org/docs/basics/UsageWithReact.html

@gaearon dalam contoh aktual Anda di dokumen Redux tampaknya komponen dapat memiliki kontainer sebagai anak.
Apakah aku salah? Bagaimana hal ini dapat memengaruhi testabilitas komponen bodoh yang membuat di dalamnya menjadi cerdas?
Namun saya tidak menemukan cara untuk membiarkan komponen menjadi yang terbaru dalam hierarki ...

Saya memiliki aplikasi yang membuat komponen Daftar Data Sederhana (Bodoh).
Di dalamnya setiap item harus terhubung ke toko, jadi itu yang Cerdas.

Tidak apa-apa menurut dok, tapi bisakah itu membawa masalah?

Terima kasih!

Bagaimana hal ini dapat memengaruhi testabilitas komponen bodoh yang membuat di dalamnya menjadi cerdas?

Hal ini membuat pengujian sedikit lebih sulit untuk disiapkan (Anda juga perlu menginisialisasi toko). Jika ini merupakan ketidaknyamanan, ekstrak lebih banyak komponen penyajian yang menerima children sehingga Anda dapat meneruskan komponen kontainer di dalamnya. Secara umum, pembagiannya terserah Anda, dan Anda perlu mengevaluasi pengorbanannya (kemudahan penulisan, pemfaktoran ulang, pengujian, dll), dan memilih cara memisahkan komponen untuk Anda sendiri.

Oke, jadi tidak ada cara yang benar. Kami harus mengevaluasi kasus per kasus .. Banyak
Terima kasih!!

Il lunedì 8 febbraio 2016, Dan Abramov [email protected] ha
scritto:

Bagaimana hal ini dapat memengaruhi testabilitas komponen bodoh yang dirender di dalamnya
yang pintar?

Hal ini membuat pengujian sedikit lebih sulit untuk disiapkan (Anda perlu menginisialisasi
toko juga). Jika ini merupakan ketidaknyamanan, ekstrak lebih banyak
komponen penyajian yang menerima anak-anak sehingga Anda dapat melewati wadah
komponen di dalamnya. Secara umum, pembagiannya terserah Anda, dan Anda harus melakukannya
mengevaluasi pengorbanan (kemudahan menulis, refactoring, pengujian, dll), dan
pilih cara memisahkan komponen untuk Anda sendiri.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/rackt/redux/issues/756#issuecomment -181143304.

Luca Colonnello
+39 345 8948718
luca. [email protected]

Bagaimana dengan 'komponen tata letak'? Maksud saya, ketika Anda memiliki banyak wadah yang perlu berada dalam satu komponen untuk meneruskannya ke router / navigator, komponen pembungkus ini akan menjadi 'wadah penyajian wadah yang bodoh' bukan?

@ Emilios1995 Saya memiliki masalah yang sama ...
Saya memiliki komponen Halaman yang digunakan di dalam komponen tata letak.
Komponen Layout ini memiliki menu, headers, footer .. Kontennya adalah anak yang diteruskan oleh Page to Layout ..
Menu dan header adalah wadah !! Jadi, Layout berpotensi menjadi sebuah wadah, tetapi tidak terhubung ke toko ..

Namun, jika saya mencoba meneruskan ke tata letak menu dan header, saya memiliki halaman (wadah) yang membuat tata letak (komponen) dan meneruskan ke menu dan header (wadah).

Melakukan ini hierarkinya benar, tetapi saya harus mengulang menu dan header di setiap halaman, dan sebagian dari mereka sama di setiap halaman untuk saya ..

@LucaColonnello Saya tidak begitu memahami masalah tanpa kodenya. Bolehkah saya meminta Anda untuk membuat pertanyaan StackOverflow dengan contoh sederhana yang menggambarkan masalah Anda? Dengan senang hati saya akan melihatnya.

secepat mungkin

Il sabato 27 febbraio 2016, Dan Abramov [email protected] ha
scritto:

@LucaColonnello https://github.com/LucaColonnello Saya kurang paham
memahami masalah tanpa kode. Bolehkah saya meminta Anda untuk membuat file
Pertanyaan StackOverflow dengan contoh sederhana yang menggambarkan masalah Anda? Indo
dengan senang hati melihatnya.

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/reactjs/redux/issues/756#issuecomment -189672067.

Luca Colonnello
+39 345 8948718
luca. [email protected]

Saya pikir artikel Dan tentang medium
https://medium.com/@dan_abramov/smart -and-dumb-components-7ca2f9a7c7d0 # .3y00gw1mq
mengklarifikasi semua masalah ...

01-01-2016 18:19 GMT + 01.00 Emilio Srougo [email protected] :

@gaearon https://github.com/gaearon Ini bukan masalah, saya pikir itu
lebih tepatnya pertanyaan yang saya buat di sini:
http://stackoverflow.com/questions/35729025/should-the-route-handlers-use-containers-or-presentational-components?noredirect=1#comment59133192_35729025

-
Balas email ini secara langsung atau lihat di GitHub
https://github.com/reactjs/redux/issues/756#issuecomment -190820426.

Luca Colonnello
+39 345 8948718
luca. [email protected]

@ Gaearon Saya ingin tahu bahwa jika komponen presentasi mungkin berisi komponen wadah di dalamnya, bagaimana dapat digunakan kembali?
FYI:

Saya ingin tahu bahwa jika komponen presentasi mungkin berisi komponen wadah di dalamnya, bagaimana dapat digunakan kembali?

Jika semua skenario penggunaannya menyertakan wadah tertentu di dalamnya, saya tidak melihat apa yang tidak dapat digunakan kembali tentang itu. Dan jika tidak, buatlah menerima this.props.children dan membuat komponen presentasi lainnya yang melewatkan wadah tertentu atau komponen presentasi di dalamnya.

@ Gaearon Apakah komponen container [Root component] di React-Router?

  • route.js
<Route path="/" component={Root}>
      <IndexRoute component={Main} />
      <Route path="/account/signIn" component={SignIn} />
</Route>
  • root.js
export default class Root extends React.Component {
  render() {
    return (
      <div>
        <div id="container" className="container">
          {this.props.children}
        </div>
      </div>
    );
  }

Terima kasih.

@gaearon di atas Anda mengatakan bahwa Anda lebih suka menyambungkan komponen untuk mendapatkan akses ke pengiriman (daripada meneruskannya dari komponen induk).

Jika Anda menghubungkan komponen ini, dan mereka juga memiliki props yang _dapat_ dipetakan dari reduksi yang saat ini sedang diteruskan oleh induk, apakah Anda akan memfaktorkan ulang ini menjadi dari connect ? Atau gunakan ownProps untuk membuatnya tetap diteruskan oleh orang tua.

Apakah ada perbedaan fungsional / kinerja antara kedua opsi tersebut?

Saya tidak memiliki banyak pengalaman bekerja dengan proyek redux besar tetapi saya telah meneliti dan berpikir banyak tentang mengoptimalkan struktur file react / redux. Beri tahu saya jika ini masuk akal atau tidak:

src/
  components/
    header/ 
      navigation.js # nav menu list
      index.js # Header component
  modules/
    header/
      actions.js # header actions (sticky scroll, collapse mobile menu, etc...)
      reducer.js # header actions reducer (export to modules index)
      index.js # HeaderContainer (connect to Header component)
    index.js # combineReducers and export default configureStore (and middleware)

konsep lain:

src/
  components/
    navigation.js
    logo.js
    link.js
    list.js
    item.js
  modules/
    header/
      actions.js # header actions 
      wrapper.js # header class (smart) component - to wrap header with functionality (was previously classified as container)
      container.js # header functional (dumb) component - to contain universal components
      index.js # header actions reducer - to export into modules rootReducer 

Atau lebih baik memisahkan komponen, kontainer, dan modul redux (meskipun mereka memiliki nama yang sama)? Terima kasih atas masukannya.

Saya telah bekerja dengan proyek react-redux tingkat perusahaan dan melalui pengalaman saya, saya dapat mengatakan satu hal bahwa itu semata-mata tergantung pada Anda bagaimana mendefinisikan arsitektur proyek Anda. Saya tidak mengikuti variasi arsitektur berbasis container / komponen karena tidak praktis dalam arti bahwa tujuan React adalah membuat UI berbasis komponen yang dapat digunakan kembali.

Jadi saya telah menemukan pendekatan sederhana untuk mengelompokkan seluruh proyek berdasarkan Modul dan telah bekerja dengan sangat baik sampai sekarang dalam hal skalabilitas, pemeliharaan, dan keterbacaan kode.

image
image
image

Bagi saya, container dan smart-component sama persis. Definisi sederhananya adalah:
Container / smart-component adalah yang berisi markup JSX + event handler + panggilan api + connect / MSTP / MSDP dari redux.
Komponen bodoh adalah komponen presentasi dan fungsional MURNI.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat