Redux: الحاوية مقابل المكون؟

تم إنشاؤها على ١٩ سبتمبر ٢٠١٥  ·  46تعليقات  ·  مصدر: reduxjs/redux

في الأمثلة يوجد دائمًا مجلد يسمى "container" وآخر يسمى "component". ما هو الفكر من وراء هذا الانفصال؟

هل "الحاويات" مكون ذكي أم أنها تقوم بتوجيه المكونات أو أي شيء آخر؟ هل يجب أن تكون المكونات الموجودة ضمن "المكونات" غبية دائمًا؟

docs question

التعليق الأكثر فائدة

أدعو components مكونات React المغلفة التي تحركها الدعائم فقط ولا تتحدث إلى Redux. مثل "المكونات الغبية". يجب أن تظل كما هي بغض النظر عن جهاز التوجيه الخاص بك ، ومكتبة جلب البيانات ، وما إلى ذلك.

أتصل بمكونات containers React التي تدرك Redux و Router وما إلى ذلك ، فهي أكثر ارتباطًا بالتطبيق. مثل "المكونات الذكية".

ال 46 كومينتر

بالنسبة لي ، container هو معالج المسار ، والذي يسحب أيضًا حالة redux لهذا المسار. ثم أقوم بتمرير حالتي كدعم.

على سبيل المثال،

حاويات / خصائص. 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;

وعلى سبيل المثال ،

المكونات / الخصائص / 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;

القراءة من الروابط التي قدمتها:

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

ينتابني شعور أكثر بأن "الحاويات" هي في الواقع ما يسمى في إعادة التشغيل "المكونات الذكية" ... ويجب أن تحصل المسارات / الصفحات على مجلد خاص بها.

لست متأكدًا من سبب ارتباط "الحاوية" و "معالجات المسار" بأي شكل من الأشكال؟

من الشائع جدًا تجميع مكونات تطبيقك حسب المسار. كما أشار theaqua ، من الشائع أيضًا جعل كل معالج / مكون للطريق مكونًا ذكيًا / حاوية. إذا كنت تستخدم CombReducers ، فغالبًا ما تجد نفسك تفكك الحالة والطرق والحاويات على طول نفس الخطوط. وبالتالي ، غالبًا ما يترابطون معًا.

لمronag أنا لا أعتقد أنك تحتاج إلى جعل الحاويات والصفحات. لماذا لا يمكنك وضع معالج المسار وموصل الإعادة في مكان واحد؟ إنه سهل الاستخدام. أبقيها بسيطة.

في طلبي لدي 3 مسارات / صفحات فقط. من ناحية أخرى ، لدي الكثير من اللوحات / الوحدات المستقلة. إن الحصول على connect ضخم واحد

إذا قمت بإجراء جميع عمليات التعيين من الحالة إلى الدعائم وجلب جميع البيانات في ملف واحد ، فسيكون ذلك غير قابل للاستمرار. خاصة إذا قمت بإحضار جميع البيانات في نفس الموقع.

إذا كان لديك 3 مسارات ، فأنت بحاجة إلى 3 معالجات للطرق. على سبيل المثال ، A.jsx ، B.jsx ، C.jsx في /containers .

في كل حاوية تقوم بسحب جزء (ليس بالكامل!) من حالة إعادة الإرجاع وربط الإجراءات. ثم تقوم بتمرير هذا إلى مكونات كما في المثال الخاص بي. إنه قابل للصيانة للغاية ، لأنني (وفريقي) أعلم - الاتصال بالإعادة وربط الإجراءات دائمًا في containers ، لن يكون في components (وهو صغير وغالبًا ما يكون عديم الجنسية كما في المثال ).

أعتقد أنني أفهم اقتراحك. ومع ذلك ، كما قلت ، ستصبح هذه الملفات الثلاثة معقدة للغاية إذا وضعت جميع بياناتي التي أحضرها هناك. في قضيتنا سيكون "تسجيل الدخول ، التطبيق ، تسجيل الخروج" حيث سيحتوي التطبيق على كل شيء تقريبًا.

ربما أكون متحيزًا جدًا إلى Relay حيث يحتوي كل مكون على حاوية تصف البيانات التي يجب جلبها وكيف يجب أن تبدو.

سأحاول اقتراحك ونرى أين ننتهي.

أدعو components مكونات React المغلفة التي تحركها الدعائم فقط ولا تتحدث إلى Redux. مثل "المكونات الغبية". يجب أن تظل كما هي بغض النظر عن جهاز التوجيه الخاص بك ، ومكتبة جلب البيانات ، وما إلى ذلك.

أتصل بمكونات containers React التي تدرك Redux و Router وما إلى ذلك ، فهي أكثر ارتباطًا بالتطبيق. مثل "المكونات الذكية".

gaearon : ممتاز. هذا يوضح الأمثلة. شكرا لك.

gaearon لذا فإن "المكونات الغبية" هي مكونات عديمة الحالة ، والتي يمكن كتابتها بصيغة أبسط منذ React 0.14 ، على سبيل المثال:

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

هل انا صائب؟

تضمين التغريدة

ليس بالضرورة. بناء الجملة ليس هو الهدف.

المكونات "الغبية" المعروفة أيضًا باسم المكونات "التقديمية" هي مكونات تتلقى جميع البيانات عن طريق الدعائم ، ولا تدرك Redux ، وتحدد فقط المظهر وليس السلوك.

تضمين التغريدة

على الرغم من أن مصطلح "الحاوية" شائع بالفعل في تسميات التفاعل / الإعادة ، فقد قررنا تسميتها "الموصلات" في المشروع الذي أعمل عليه ، لتجنب أي ارتباك مع حاويات التخطيط / الرسوم.

راجع للشغل ، تمت مناقشة كيفية الاتصال بهم سابقًا هنا: Rackt / reaction-redux # 170. احتفظ بكل شيء داخل مجلد components والمجلدات التقديمية أعمق بمقدار مستوى واحد ، داخل components/presentational ، وأعتقد أنه جيد لأنه من غير المحتمل أن تكون هناك حاجة إلى أجزاء من التطبيق بخلاف الحاويات.

gaearon إذن هو المكون الذي dispatch "غبيًا" أو "ذكيًا"؟ من المفيد بشكل خاص أن يكون لديك عنصر طرفية أو وسيط لإرسال إجراء بدلاً من إعادة الحدث إلى المكون العلوي للقيام بالإرسال.

نعم ، يمكن أن يكون مفيدًا في بعض الأحيان على الرغم من أنني أفضل connect() مثل هذه المكونات ، لذلك يتم حقن منشئ الإجراء كدعم. لا يهم حقًا كيف تسميها :-)

ماذا عن عندما تقوم ببناء وحدة من المكونات؟ على سبيل المثال ، لنفترض أن لدي وحدة عقدة منفصلة لقائمة التنقل الخاصة بنا <NavMenu> أريد أن يقوم الأشخاص بعمل رمز مثل هذا:

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

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

فهل أسميها "NavMenuContainer"؟ هذا يبدو غريبا بالنسبة لي. هل يجب علي تسمية المكون NavMenuComponent بدلاً من ذلك؟ كلاهما يبدو غريبًا بالنسبة لي. في هذه الحالة ، يتصل المكون فقط بالمكالمات للحصول على حقل واحد من الحالة. هل من السيء حقًا تضمين المكالمة للاتصال بهذه الطريقة؟

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

أشعر بالفضول لسماع أفكارك على لتضمين مكالمة الاتصال ...

لا يهم كيف تسميها. لماذا لا تسميها NavMenu ؟

أنا لا أفهم السؤال حول التضمين.
سيكون من المفيد إذا قدمت نهجين تقارنانهما.

حسنًا على سبيل المثال.
الخيار 1 (ملفان منفصلان ، 1 للحاوية ، 1 للمكون)

حاويات / NavMenu

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

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

الخيار 2 (ملف واحد يحتوي على كليهما):
المكونات / 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>;
  }
});

ما أعنيه بالتضمين هو مجرد وجود ملف واحد (على عكس ملفين) وهو كل من الحاوية والمكون نظرًا لوجود جزء بسيط واحد فقط حول المسار الحالي المطلوب من الحالة. هل هذا مجرد شيء يجب تجنبه دائمًا أم أنه من المعقول القيام به في حالات بسيطة مثل هذه؟

بالتأكيد ، من المعقول القيام بذلك في حالات بسيطة.

حسنا رائع. متى ترسم الخط وتقول "حسنًا ، سأقوم بنقل هذا إلى ملفين منفصلين"؟

عندما يبدأ المكون في مزج مخاوف البيانات (كيفية استرداد / حساب البيانات ، وكيفية إرسال الإجراءات) مع العرض التقديمي (كيف يبدو). عندما يصبح من الصعب الاختبار أو إعادة الاستخدام في سياق مختلف.

benmonro فكر واحد آخر. إذا كنت تقوم بإنشاء وحدة نمطية من المكونات ، فقد ترغب في بعض الأحيان في توصيل هذه المكونات بأجزاء مختلفة من شجرة حالة التطبيق الخاص بك ، أو اختبار العرض التقديمي بشكل منفصل مع حالات مختلفة. في هذه الحالة ، فإن وجود connect داخل وحدة المكونات هذه سيحد من هذه القدرة.

شكرا جايرون

sompylasar نقطة جيدة جدا! شكرا

حسنًا ، بعد مراجعة الكود الخاص بي لإعادة تشكيله لتقسيمه ، لدي الآن سؤال متابعة. افترض أن لدي أيضًا حاوية <NavMenuItem> . يحتاج المكوِّن <NavMenu> إلى الإشارة إلى <NavMenuItem /> كعنصر فرعي. هل يجب أن أفعل فقط import NavMenuItem from '../containers/NavMenuItem' في مكون NavMenu؟ كيف يؤثر هذا على قابلية الاختبار compylasar @؟

أود أن أجعل NavMenuItem مكونًا عرضيًا خالصًا مع تمرير جميع البيانات المطلوبة إليه عبر الدعائم بواسطة NavMenu. سيسمح هذا باختباره بشكل منفصل. لذلك ، سيكون لديك مكونان عرضيان (NavMenu و NavMenuItem) وواحد متصل (connect (...) (NavMenuItem)).

هناك شيء مفقود في هذه المناقشة: عندما يكون لديك في ملف واحد ، لا يمكنك استخدام العرض الضحل للاختبار. لقد رأيت أشخاصًا يعرضون كلاً من المكون التقديمي ومكون الحاوية للتغلب على هذا ، ثم اختبروه بشكل منفصل ، لذلك في هذه الحالة أفضل أن يكون لدي ملفين لتوضيح أن هذين شيئين. وهذا يسلط الضوء أيضًا على فصل الاهتمامات هنا وحقيقة أن المكون التقديمي مستقل وقابل لإعادة الاستخدام.

FWIW لقد قمت بتحديث مقالة العرض ومكونات الحاوية لتعكس تفكيري الحالي.

لم نعد نشجع إنشاء مكونات حاوية في المستندات المحدثة.
http://redux.js.org/docs/basics/UsageWithReact.html

gaearon في المثال الفعلي الخاص بك في مستند Redux يبدو أن المكونات يمكن أن تحتوي على حاويات مثل الأطفال.
هل انا مخطئ كيف يمكن أن يؤثر ذلك على قابلية اختبار المكون الغبي الذي يجعل بداخله عنصرًا ذكيًا؟
ومع ذلك ، لا أجد طريقة لجعل المكونات هي الأحدث في التسلسل الهرمي ...

لدي تطبيق يعرض مكون قائمة بيانات بسيطة (غبي).
بداخله ، يجب توصيل كل عنصر بالمتجر ، لذا فهو عنصر ذكي.

لا بأس وفقًا للمستند ، لكن هل يمكن أن يؤدي إلى بعض المشاكل؟

شكر!

كيف يمكن أن يؤثر ذلك على قابلية اختبار المكون الغبي الذي يجعل بداخله عنصرًا ذكيًا؟

هذا يجعل الاختبار أكثر صعوبة في الإعداد (تحتاج إلى تهيئة المتجر أيضًا). عندما يكون هذا أمرًا مزعجًا ، فاستخرج المزيد من مكونات العرض التي تقبل children حتى تتمكن من تمرير مكونات الحاوية إلى الداخل. بشكل عام ، فإن التقسيم متروك لك ، وتحتاج إلى تقييم المقايضات (سهولة الكتابة ، وإعادة البناء ، والاختبار ، وما إلى ذلك) ، واختيار كيفية فصل المكونات بنفسك.

حسنًا ، ليس هناك طريق صحيح. علينا أن نقيم كل حالة على حدة .. كثير
شكرا!!

Il lunedì 8 فبراير 2016 ، Dan Abramov [email protected] هكتار
سكريتو:

كيف يمكن أن يؤثر ذلك على قابلية اختبار المكون الغبي الذي يظهر بداخله
ذكي؟

هذا يجعل الاختبار أكثر صعوبة في الإعداد (تحتاج إلى التهيئة
المتجر أيضًا). عندما يكون هذا مصدر إزعاج ، استخرج المزيد
المكونات التقديمية التي تقبل الأطفال حتى تتمكن من تمرير الحاوية
المكونات في الداخل. بشكل عام ، التقسيم متروك لك ، وتحتاج إلى ذلك
تقييم المقايضات (سهولة الكتابة ، إعادة البناء ، الاختبار ، إلخ) ، و
اختر كيفية فصل المكونات بنفسك.

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/rackt/redux/issues/756#issuecomment -181143304.

لوكا كولونيلو
+39 345 8948718
لوكا. [email protected]

ماذا عن "مكونات التخطيط"؟ أعني أنه عندما يكون لديك العديد من الحاويات التي يجب أن تكون في مكون واحد لتمريرها إلى جهاز التوجيه / الملاح ، فإن مكون التغليف هذا سيكون "حاوية عرض غبية للحاويات" ، أليس كذلك؟

@ Emilios1995 لدي نفس المشكلة ...
لدي مكون صفحة يستخدم داخل مكون تخطيط.
يحتوي مكون التخطيط هذا على قوائم ورؤوس وتذييل .. والمحتوى هو العنصر الفرعي الذي تم تمريره من الصفحة إلى التخطيط ..
القوائم والرؤوس حاوية !! لذا من المحتمل أن يكون Layout عبارة عن حاوية ، ولكنه غير متصل بالمتجر ..

ومع ذلك ، إذا حاولت التمرير لتخطيط القوائم والرأس ، فلدي صفحة (حاوية) تعرض التخطيط (المكون) وتمريرها إلى القوائم والعناوين (الحاويات).

إن القيام بهذا التسلسل أمر صحيح ، لكن لا بد لي من تكرار القوائم والعناوين في كل صفحة ، وبثها هي نفسها في كل صفحة بالنسبة لي ..

LucaColonnello أنا لا أفهم المشكلة تمامًا بدون الرمز. هل لي أن أطلب منك إنشاء سؤال StackOverflow مع مثال بسيط يوضح مشكلتك؟ سأكون سعيدا لإلقاء نظرة.

في اسرع وقت ممكن

Il sabato 27 febbraio 2016 دان أبراموف [email protected] هكتار
سكريتو:

LucaColonnello https://github.com/LucaColonnello أنا لست تمامًا
فهم المشكلة بدون الكود. هل لي أن أطلب منك إنشاء ملف
سؤال StackOverflow مع مثال بسيط يوضح مشكلتك؟ هوية شخصية
كن سعيدا لإلقاء نظرة.

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/reactjs/redux/issues/756#issuecomment -189672067.

لوكا كولونيلو
+39 345 8948718
لوكا. [email protected]

أعتقد أن مقال دان عن المتوسط
https://medium.com/@dan_abramov/smart-and-dumb-component-7ca2f9a7c7d0 # .3y00gw1mq
يوضح كل القضايا ...

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

gaearon https://github.com/gaearon ليست مشكلة ، أعتقد أنها
بالأحرى سؤال طرحته هنا:
http://stackoverflow.com/questions/35729025/should-the-route-handlers-use-containers-or-presentational-components؟noredirect=1#comment59133192_35729025

-
قم بالرد على هذا البريد الإلكتروني مباشرة أو قم بعرضه على GitHub
https://github.com/reactjs/redux/issues/756#issuecomment -190820426.

لوكا كولونيلو
+39 345 8948718
لوكا. [email protected]

gaearon أتساءل أنه إذا كان المكون التقديمي يحتوي على مكونات حاوية بداخله ، فكيف يمكن إعادة استخدامه؟
لمعلوماتك:

أتساءل إذا كان أحد المكونات التقديمية يحتوي على مكونات حاوية بالداخل ، فكيف يمكن إعادة استخدامه؟

إذا تضمنت جميع سيناريوهات الاستخدام الخاصة به حاوية معينة بداخلها ، فلا أرى ما لا يمكن إعادة استخدامه بشأنه. وإذا لم يكن الأمر كذلك ، فاجعله يقبل this.props.children وأنشئ مكونات عرضية أخرى تمرر حاويات معينة أو مكونات عرضية بالداخل.

gaearon هل [مكوّن الجذر] هو مكوّن حاوية على 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>
    );
  }

شكرا.

لقد قلتgaearon أعلاه أنك تفضل توصيل المكونات من أجل الوصول إلى الإرسال (بدلاً من تمريرها من خلال المكونات الأصلية).

إذا قمت بتوصيل هذه المكونات ، وكان لديهم أيضًا دعائم _يمكن تعيينها _ من المخفضات التي يتم تمريرها حاليًا من قبل الوالد ، فهل يمكنك إعادة تشكيلها لتأتي من connect ؟ أو استخدم ownProps لتمريرها من قبل الوالدين.

هل يوجد فرق وظيفي / أداء بين الخيارين؟

ليس لدي الكثير من الخبرة في العمل مع مشاريع إعادة الإرسال الضخمة ، لكني كنت أبحث وأفكر كثيرًا في تحسين هياكل ملف التفاعل / الإعادة. اسمحوا لي أن أعرف ما إذا كان هذا منطقيًا أم لا:

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)

مفهوم آخر:

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 

أم أنه من الأفضل فقط الاحتفاظ بالمكونات والحاويات ووحدات إعادة الإرسال منفصلة (على الرغم من أنها تشترك في نفس الاسم)؟ شكرا على أي مساهمة.

لقد عملت مع مشاريع رد الفعل والإعادة على مستوى المؤسسة ومن خلال تجربتي ، يمكنني أن أقول شيئًا واحدًا يعتمد عليك فقط في كيفية تحديد بنية مشروعك. لا أتبع أيًا من الاختلافات المعمارية القائمة على الحاوية / المكونات لأنها غير عملية بمعنى أن هدف React هو إنشاء واجهة مستخدم قائمة على المكونات القابلة لإعادة الاستخدام.

لذا فقد توصلت إلى نهج بسيط لتجميع المشاريع بأكملها استنادًا إلى الوحدات النمطية وقد نجح بالفعل حتى الآن من حيث قابلية التوسع وقابلية الصيانة وقابلية قراءة الكود.

image
image
image

بالنسبة لي ، الحاوية والمكون الذكي متماثلان تمامًا. التعريف البسيط هو:
الحاوية / المكون الذكي هو المكون الذي يحتوي على علامات JSX + معالجات الأحداث + مكالمات api + اتصال redux / MSTP / MSDP.
المكون الغبي هو عنصر وظيفي تقديمي حقيقي.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات