مرحبًا ericanderson
أواجه العديد من المشكلات مع هذا التغيير عند استخدامه عمليًا:
عند الضغط على Go To Definition (الانتقال إلى التعريف) على خاصية props أو state ، يتعذر على Typescript حلها.
interface MyComponentProps {
name: string;
}
export abstract class MyComponent extends React.Component<MyComponentProps , void> {
myMethood() {
this.props.name; //<-- Go To definition in name
}
}
هذا منطقي لأن العضو تم إنشاؤه صناعيًا ، ولكنه مزعج على أي حال.
الأهم من ذلك ، إذا قمت بإنشاء مكون مجرد مثل هذا:
interface MyBaseProps {
onChange?: (val: any) => void;
}
export abstract class MyBase<P extends MyBaseProps> extends React.Component<P, void> {
myMethood() {
this.props.onChange!(2); //The type is S["onChange"] instead of (val: any) => void and so is not invocable.
}
}
TS قادر على إظهار أن هناك خاصية عند التغيير ، لكن في بعض الأحيان لا يستطيع اكتشاف نوعه.
هذا هو أهم تغيير لأنه إذا كان يمنعني من الحصول على تسلسلات هرمية للمكونات التي تشترك في الدعائم والوظائف المشتركة. يبدو أنه مشكلة في مترجم TS ولكن حتى يتم إصلاحها.
بينما أوافق على أن هذا التغيير يلتقط جيدًا الهدف الوظيفي لـ React ، فهناك مواقف صحيحة حيث يمكنك تعديل الحالة بشكل إلزامي ، كما هو الحال في المُنشئ ، وأيضًا إذا قمت بتغيير الحالة واستدعاء forceUpdate يعمل دائمًا على ما يرام.
C#
this.state.name = "John";
this.forceUpdate(); //Ok as long as you don't setState afterwards, but calling setState also is annoying with the callback.
هل هو موصى به؟ رقم.
هل هو ممنوع؟ أيضًا لا ، وإلا فلن توجد ForceUpdate.
بالطبع يمكنك تحويل الولاية إلى S
(أو any
) وإجراء التغيير ، لكن إذا كان النمط الشائع يصبح مرهقًا.
أشعر بالحزن لأن الميزة اللامعة الجديدة لـ TS تسبب مشاكل أكثر من الحلول في هذه الحالة ، لكنني أعتقد بصدق أن هذا هو الحال هنا.
على الجانب الآخر ، تغيير setState
رائع 👍 ، لم أكن أعرف عن Pick<S,K>
.
ما هو إصدار المطبوع على الحروف الذي يستخدمه الاستوديو المرئي الخاص بك؟
vsaio لسا
بالنسبة للمشكلة 1 ، مع TS 2.1.5 وأحدث VSCode ، هذا يعمل بشكل جيد بالنسبة لي. ليس لدي windows / VS لذا لا يمكنني التحقق هناك ، لكنني أراهن أن هناك تحديثات للمكونات الإضافية أو أنك لست على TS 2.1.5
نفس الشيء بالنسبة للمشكلة 2
VS 2015 مع TS 2.1.5.0
أعتقد أن المشكلة 3 مطروحة للنقاش.
أنت محق في أنه يمكنك _تقنيًا_ عمل المثال أعلاه في React ، لكنني سأجادل بالتأكيد أن هذه ليست الطريقة التي كان يُقصد من استخدام React بها.
يمكن تقسيم هذا إلى 3 حالات متميزة.
interface State {
bar: number;
}
interface Props {
baz: number;
}
class Foo extends React.Component<Props, State> {
public state: State = {
bar: 5,
};
}
interface State {
bar: number;
}
interface Props {
baz: number;
}
class Foo extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
bar: props.baz,
};
// or
this.setState({
bar: props.baz,
});
}
}
forceUpdate
نظرًا لأنني أعتقد أنه من الأفضل دفع الأشخاص نحو الشيء "الصحيح" ، يمكنك بسهولة حل هذه المشكلة عن طريق إعادة إعلان public state
:
interface State {
bar: number;
}
class Foo extends React.Component<{}, State> {
public state: State;
public myMethod() {
this.state.bar = 5;
}
}
مشكلتي مع تباين الأدوية. خصيصًا للكتابة داخل الفصل الذي يتم كتابته بشكل عام. أدناه عينة صغيرة جدًا من الأماكن التي تتعطل فيها الأشياء.
class TBaseState {
public value: string;
}
function globalFunc<T extends Readonly<TBaseState>>(item: T) {
}
class MyComponent<TProps, TState extends TBaseState> extends React.Component<TProps, TState> {
broken() {
// typing of this.state is Readonly<TState>
// this is not assignable to Readonly<TBase>
globalFunc(this.state);
// this is a horrible hack to fix the generics variance issue
globalFunc(this.state as TState as Readonly<TBaseState>);
}
}
class MyState extends TBaseState {
}
let component: MyComponent<any, MyState>;
// here the typing of component.state is Readonly<MyState>
// this is assignable to Readonly<TBase>
globalFunc(component.state);
أنا في TS 2.1.5.0
ولكن يمكن أن يكون لدينا في VS تجربة TS أسوأ مما كانت عليه في رمز VS ...
بالنسبة للمشكلة 1 ، انتقل إلى التعريف لا يعمل TS أيضًا في رمز VS:
interface MyComponentProps {
name: string;
}
export abstract class MyComponent extends React.Component<MyComponentProps , void> {
fullName: string;
myMethood() {
this.props.name; //<-- doesnt work
this.fullName; //<-- works
}
}
بالنسبة للمشكلة 2 ، من الصحيح أن VS Code يتصرف بشكل أفضل:
بينما يبدو VS مرتبكًا:
أعتقد أنه بالنسبة لـ VSCode والمشكلة 1 ، يعمل هذا لأنني أستخدم المكون الإضافي لـ "أحدث نسخة من القواعد النحوية وجافا سكريبت" والتي يجب أن تتمتع بمعالجة أكثر ذكاءً.
patsissons هذا مثال مثير للاهتمام ، على الرغم من أنني أعتقد أنه يمثل خطأ في الكتابة المطبوعة أكثر من خطأ في ملف التعريف. على سبيل المثال ، استخدم setState
لأخذ S
وهو ما يعني القيام ببعض الحيل التي اعتدنا عليها القيام بحيل غريبة مثل setState({foo:5} as any as State)
أو استخدام الحيل التي تأخذ وظيفة. لست متأكدًا من أن الافتقار إلى التعبيرية للمترجم يجعل الكتابة "خاطئة". أعتقد أن هذه حجة جيدة لإجراء تغيير في README لوضع علامة على حالة الحافة هذه.
هل قمت بتقديم مشكلة بخصوص TS؟
لذا فإن هذا التغيير في الوقت الحاضر يكسر جميع VS ويعطل Go To Definition في جميع رموز VS إلا إذا كان لديك مكون إضافي ...
هناك أيضا حجة الاكتمال. هناك عدد قليل من واجهات برمجة التطبيقات التي من المفترض أن تكون للقراءة فقط وليست في الوقت الحاضر ، فقط في React.d.ts
interface ComponentLifecycle<P, S> {
componentWillMount?(): void;
componentDidMount?(): void;
componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): boolean;
componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: Readonly<any>): void;
componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, prevContext: Readonly<any>): void;
componentWillUnmount?(): void;
}
أعتقد أنه يجب استخدام "القراءة فقط" لـ "التجميد" أو "Inmmutable.js" وليس للذيل الطويل من الأفكار التي لا يُقصد تعديلها ، مثل كائنات الأحداث ، على سبيل المثال.
لم يتم التقديم ، لقد قمت فقط بتعديل الكود الخاص بي اليوم للتعامل مع أنواع Readonly<T>
الجديدة ، كانت هذه حالة واجهتني ولم يكن لدي حل مكتوب بشكل صحيح. انطلق وقدم مشكلة ، سأكون مشغولاً معظم اليوم ببقية كود الترقيع.
آه نعم ، كنت أعلم أنني فاتني البعض. olmobrutall إذا احتفظنا بتغييرات الحالة التي أدخلتها لوضع علامة "للقراءة فقط" ، فأنا أوافق على ضرورة تحديث هذه الأساليب. أشعر أننا بحاجة إلى إجماع على الشيء الصحيح الذي يجب القيام به أولاً.
بالنسبة إلى فواصل VS ، لا أعرف ما هو الصواب. هل يجب تأجيل الأنواع لأن بعض الأدوات لا يتم تحديثها؟
patsissons يمكنك دائمًا تقديم كتاباتك الخاصة للتفاعل الآن إذا كنت تريد الانتظار لترى كيف سينتهي هذا الأمر قبل تحديث كل التعليمات البرمجية الخاصة بك. https://ericlanderson.com/using-custom-typescript-definitions-with-ts-2-x-3121db84015d#.ftlkojwnb
في تجربتنا ، VS دائمًا متخلف قليلاً. يستخدم متجرنا vscode للقيام بأي تطوير فعال للنص المطبوع ويتم استخدام VS بشكل أكبر لمجرد تصحيح ملفات التعليمات البرمجية أو للمطورين الذين لا يستخدمون النصوص المطبوعة للبحث في التعليمات البرمجية ، وليس بالضرورة من أجل التطوير النشط.
ericanderson أن الاختراق ليس سيئًا للغاية في الوقت الحالي ، فأنا فقط بحاجة إلى تذويب Readonly<T>
للحصول على T
الذي يمكن تخصيصه لـ Readonly<Base>
.
نحن نتحدث عن "رد فعل d.ts" ، يتم استخدام تصريح العضو الواحد هذا على نطاق واسع. أعتقد أن الأمر يستحق التراجع حتى يصبح VS جاهزًا.
أيضًا ، مثل 50٪ من الأنواع في العالم من المفترض أن تكون للقراءة فقط ، مثل الكائنات التي تحصل عليها من واجهات برمجة التطبيقات ، لا أعتقد أننا بحاجة إلى إضافة تعليق توضيحي لذلك.
أعتقد أنه يجب استخدام Readonly للكائنات التي تم تحويلها صراحةً إلى خصائص get-only. مثل التجميد.
olmobrutall Readonly
جديد ، لذا لم يتم تحديد أفضل الممارسات بالضبط. أنا شخصياً أفضل أن يعلن كل شيء أن الأمر يتطلب Readonly<>
من الأشياء للمساعدة في الإشارة إلى أنه لن يغيرها. وبالمثل ، لا تتوقع منك React تعديل state
خارج setState
وبالتالي يضمن هذا التغيير أن الحوادث لا تسبب أخطاء ، وهي إحدى الفوائد الأساسية لاستخدام TypeScript على جافا سكريبت.
إذا كان الأداء أكثر اتساقًا عبر المتصفحات مقابل Object.freeze
، أتخيل أن أعضاء React سيبدأون بالفعل في التجمد بعد setState
.
ما هو الغرض من ForceUpdate إذن؟
أشعر بالفضول حيال أفكار الأشخاص الآخرين حول كيفية عمل DefinitelyTyped فيما يتعلق بتحديثات الأدوات بالإضافة إلى فلسفة حول Readonly في رد الفعل (والمكتبات الأخرى التي تهدف إلى عدم تعديل كائنات معينة).
cc / johnnyreillyvsaio @ pspeter3 للاطلاع على أفكار حول الرد على وجه التحديد والأفكار الأخرى بشكل عام
cc / @ andy- msmhegazy للحصول على أفكار حول كيف يجب أن يتم تطبيق DefinitelyTyped على العمل فلسفيًا لتحديثات الأدوات والاستخدام الحماسي لـ Readonly
olmobrutall نستخدم forceUpdate
لوضع عرض في قائمة الانتظار على جانب التفاعل ، مدفوعًا من الأحداث التي يمكن ملاحظتها على جانب الولاية.
تحديث :
سأوضح السيناريو الخاص بنا قليلاً حتى لا يساء فهمه. كائنات حالتنا هي كائنات غير قابلة للتغيير وتعيش طويلاً (لذا فإن Readonly<T>
مناسب جدًا لنا). تحتوي كائنات الحالة هذه على عدة تدفقات يمكن ملاحظتها rxjs
والتي توجه إلى إشعار يمكن ملاحظته يسمى stateChanged
. تراقب مكونات React هذا الذي يمكن ملاحظته للأحداث وتقوم بتحويل تلك الأحداث إلى مكالمة إلى forceUpdate
(بعد الرفض). في الواقع ، تعيش دولتنا المتغيرة داخل الدولة ، لكن الدولة نفسها والأعضاء الموجودون فيها جميعًا غير قابلين للتغيير. هذه بالتأكيد ليست حالة الاستخدام القياسية لـ React ، لكنها متشابهة جدًا في التدفق. لدينا ببساطة كائنات حالة ذكية تعرف كيفية إبلاغ المكونات عند الحاجة إلى إعادة العرض.
ericanderson المشكلة الرئيسية هي أن تعريفات الأنواع هذه تعاني من مشكلات SemVer. نظرًا لأن إصدارات تعريف النوع مرتبطة إلى حد كبير بإصدارات الوحدة النمطية الخاصة بها ، فإننا ننتهي مع نتوء إصدار ثانوي يؤدي إلى تغييرات تعريف النوع المتكسر ، مما يعني أنه يتعين علينا تثبيت إصدارات @types
في package.json
ملف.
olmobrutall من مستندات الرد:
عادة يجب أن تحاول تجنب كل استخدامات forceUpdate () والقراءة فقط من this.props و this.state في العرض ().
يخبرك دليل التفاعل في الواقع بعدم تحديث الحالة مباشرة: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-edit-state-مباشرة
forceUpdate
، كما قرأته ، هو فقط لإجبار المكون الخاص بك على التحديث عندما يعتمد المكون الخاص بك على البيانات _ لا _ في الدعائم الخاصة بك أو حالتك.
patsissons قد أكون مخطئًا ، لكنني أعتقد أن SemVer مصمم ليكون متوافقًا مع واجهات برمجة التطبيقات والأهداف الدلالية. فقط لأنك تستخدم مكتبة بطريقة لم تكن مقصودة (وفقًا للمستندات) لا يعني أن المكتبة يجب أن تستمر في دعم الاستخدامات غير المقصودة المذكورة. مؤلفو المكتبة جيدون في SemVer لتغيير الدلالات التي كانت غير صحيحة ولكن تم استخدامها من قبل بعض الناس.
ومع ذلك ، ربما يكون Readonly<>
إلى state
تغييرًا كبيرًا جدًا ، لكن افترض للحظة أنه التغيير الصحيح. متى يجب تحريرها في DefinitelyTyped؟ ستعاني شفرتك دائمًا من الحاجة إلى التغيير بمجرد حصولك على التحديث الذي يشير أخيرًا state
كـ Readonly<>
.
ما زلت لا أعرف ما هو الصحيح حول تطبيق Readonly<>
على state
مما يجعل من الصعب مناقشة semver أو الأدوات أو أي شيء آخر. كان حدسي أنه كان على حق. الأشخاص الذين راجعوا التغيير لم يطرحوه أبدًا على أنه مشكلة. يبدو أنه يتماشى مع نية فريق React.
يسعدني أن أرجع إلى أي من المراجعين للتفاعل في DefinitelyTyped (لقد قمت بنسخهم جميعًا أعلاه).
لذا فإن المرصد يغير الحالة وتجبر التحديث؟ لذا فإن تغيير الدولة بشكل إلزامي هو بعض الكيفية المسموح بها.
أدرك أن المكان الذي يجب استخدام Readonly فيه لم يتم تحديده بنسبة 100٪. لكن هل نحتاج إلى البدء بخاصية مثيرة للجدل ومستخدمة على نطاق واسع قبل أن تصبح الأدوات جاهزة؟
أنا جميعًا مؤيد للطباعة بشدة ، فأنا أدير 6 مشاريع جميعها مع تشيكات صارمة ، لكن الفوائد هنا أقل بكثير من المشكلات التي تنتجها حاليًا.
ericanderson أعتقد أن SemVer2 مصمم للسماح بإعلانات إصدار العقدة مثل ^15.0.0
وتوقع أن تكون أي ترقيات ثانوية أو تصحيح (على سبيل المثال ، 15.0.1
أو 15.1.0
) للوحدة شفافة أو متوافق مع الإصدارات السابقة على الأقل من منظور خارجي. ستتطلب أي ترقيات رئيسية ( 16.0.0
) تعديل إعلان الإصدار لإدخال التغيير. هذه البوابات بشكل أساسي تكسر التغييرات من إحضارها إلى نظام الكتابة. لكن حاليًا لا يمكن لإصدارات تعريف النوع أن تحيد عن الإصدار الرئيسي لإصدارات الوحدة النمطية الخاصة بها (حسب الاصطلاح) ، مما يؤدي إلى هذا الانقطاع.
الإصدار المختصر هو أن تعريفات النوع يمكن أن تحتوي على تغييرات متقطعة دون تغيير الوحدة نفسها على الإطلاق ، وتتطلب التغييرات التالفة نتوءًا رئيسيًا في الإصدار.
لكنك لن تقوم بعمل ForceUpdate لإزالة العلاقات العامة ، أليس كذلك؟
ثم إذا كان forceUpdate موجودًا ، فيجب أن يكون هناك تغيير حتمي للحالة أيضًا.
من الناحية النظرية ، يجب عليك استخدام رسم بياني عميق غير قابل للتغيير ، ولكن في كثير من الأحيان يكون تغيير الحالة حتميًا على ما يرام ولا يشتري جميع المطورين فكرة هياكل البيانات المستمرة.
لحسن الحظ ، تسمح React بمسار scape وإجراء تغييرات مباشرة في الحالة الممكنة ، فهل سنمنع مطوري TS من اتخاذ هذا الطريق؟ أليس هذا أبويًا جدًا؟
على سبيل المثال ، يروج Vue.js للتغييرات الحتمية ، ولن أتفاجأ إذا كان يؤثر على React.
كما أنني كنت أقرأ منشور مدونة لبعض مؤلفي React منذ وقت ليس ببعيد (يمكنني أن أتذكر) يشجع على استخدام React بدون كل حفل Redux.
موقفي بخلاف ذلك هو نشر تعريفات الأنواع في أسرع وقت ممكن ، شاغلي الوحيد هو الأتمتة. نظرًا للحالة الحالية لتعريف النوع ، يمكن أن ينكسر بناء متتالي بدون تغييرات على المصدر. هذه الأنواع من حالات فشل CI غير الحتمية مقلقة. لا أحد يريد أن يرى بنائه ينكسر لأنهم دفعوا التغيير ثم اكتشفوا أن يد التغيير لا علاقة له بكسر البناء.
بعد أن أنام عليها كانت آرائي الشخصية كالتالي:
نظرًا للأفكار المذكورة أعلاه بالإضافة إلى الحلول البديلة لتطبيقات React غير القياسية ، أعتقد أن Readonly صحيح وأن التغيير الوحيد المطلوب لتحقيق الاكتمال هو تحديث أساليب دورة الحياة لتتطابق.
أوافق على أن هذه التغييرات منطقية تمامًا ، وكانت حالة الاستخدام الخاصة بي التي تسببت في حدوث مشكلات حالة زاوية فريدة جدًا من النادر مواجهتها. من خلال تكييف قاعدة الشفرة الخاصة بي مع الدعائم والقراءة فقط للقراءة فقط ، اكتشفت بعض مشكلات الكتابة التي لا يمكن اكتشافها. لا شك في أن نشر التغييرات كان الاختيار الصحيح.
Patsisson ، باستخدام VS ، VS Code أو أي محرر آخر؟
نقطتي هي أنه بينما تروج React لمقاربة وظيفية ، فإنها تسمح بسير عمل يشبه ألعاب الفيديو حيث يمكنك إجراء تغييرات على العالم بشكل إلزامي (حالة) ثم تقديم (forceUpdate). هذا النهج ممنوع الآن في TS. نوع من func-damentalism :)
سأفكر في بدائل لجعل نظامي البيئي الحالي قابلاً للتطبيق ثم ...
مشكلة 2 طرح الخطأ فقط مع strictNullChecks
.
[TS] Cannot invoke an expression whose type lacks a call signature. Type '((val: any) => void) | undefined' has no compatible call signatures.
+1 أنا أستخدم إجراءات صارمة
ericanderson ؟
كما هو مذكور أعلاه ، يتعلق هذا بالأدوات ، والتي من الواضح أنها خارج نطاق DT. إذا كنت تستخدم VSCode وقمت بتثبيت معاينة محلل TS القادم ، فلم أر هذه المشكلة مع strictNullChecks عندما كنت أكتب أيًا مما سبق.
ليس لدي نوافذ لذلك لا يمكنني التحدث إلى VS المناسب.
هذا التصحيح Pick
كسر الاقتراحات ضمن VSCode. عند القيام بـ this.setState({ | })
(Ctrl + Space) ، لا يتم عرض أي شيء ، على الرغم من أن الدولة محددة بوضوح واستخدام Partial<State>
لأن setState
يمكنه تعيين حالة العضو بشكل انتقائي
يجب أن يكون الرمز الصحيح IMHO هو setState(state: Partial<S>, callback?: () => any): void;
كما تمت مناقشته في فرع طلب السحب الأصلي ، بدأنا بـ Partial. ومع ذلك ، إذا كان كائن الدولة الخاص بك هو:
حالة الواجهة {
foo: سلسلة ؛
}
ثم مع جزء يمكنك القيام بما يلي:
setState ({foo: undefined}) ،
وهو أمر خاطئ بشكل واضح.
أنا آسف - ولكن مرة أخرى بخصوص Readonly
React ليست فقط Redux و setState. React هي أيضًا mobx وأنماط أخرى يمكن ملاحظتها ، حيث يكون تخصيص خصائص الحالة هو الميزة الرئيسية . يقتل التغيير الذي تمت مناقشته استخدام mobx بشكل كامل باستخدام الكتابة المطبوعة.
فلماذا تضيف السلوك غير الموجود في كود رد الفعل الأصلي إلى ملف .d.ts؟ يجب أن يكون .d.ts انعكاسًا للمكتبة الأصلية ولكن ليس تعليم الأشخاص أسلوب الترميز الصحيح ، وفقًا لوجهة نظر المؤلف!
lezious ، أخشى أنني لا أفهم موقفك. هل يمكنك تقديم عينة من التعليمات البرمجية وما الذي تم كسره في الكتابة فيما يتعلق بالعينة؟ شكرا!
لا مشكلة:
هذا هو صفي الدولة
class UserInfoBlockState
{
<strong i="7">@observable</strong> <- this is mobx way to declare state
public updating: boolean;
<strong i="8">@observable</strong>
public deleted: boolean;
}
وهذا هو المكون الخاص بي
<strong i="12">@observer</strong> <-- this is mobx way to make component react to state change
export class UserPanel extends React.Component<IUserInfoBlockProps, UserInfoBlockState>
{
......
private updateUser()
{
this.state.updating = true;
UsersAPI.update(this.props.user)
.then(() =>
{
this.state.updating = false; <--- this is the mobx way to work with the state
}
).catch(() =>
{
this.showErrror("Server error");
this.state.updating = false;
});
}
....
}
والآن نحن (شركتنا مع مشروع ضخم مكتوب على رد فعل + mobx) قمنا بتحديث DT و React في بداية دائرة الإصدار الجديد و ... أكثر من 3000 خطأ في التجميع "الخاصية للقراءة فقط". رائع. ما الذي تقترحني أن أفعله - إعادة كتابة المشروع بالكامل لإعادته ، أو عدم تحديث رد فعل d.ts مطلقًا أو الاحتفاظ بنسخة متشعبة ودعمها دائمًا؟
mweststrate ، يرجى التحقق من هذا.
Iezious أنا أقدر موقفك وأطلب منك أن تهدأ. أحاول العمل معك. هذا لا علاقة له بـ Redux ، بل علاقة بـ React النقي.
لا أريد أن يحظر DT حالة استخدام نجحت سابقًا ، ولكن لا أعتقد أن الطريقة التي تصف بها استخدام mobx مع رد فعل تتوافق مع وثائق التفاعل (ولا حتى وثائق mobx التي قرأتها الآن هو - هي).
تشير React بوضوح في الوثائق إلى أن هناك ثلاث طرق لاستخدام الحالة بشكل صحيح ، وأولها هو "عدم تعديل الحالة بشكل مباشر".
يقودني هذا إلى الاعتقاد بأن الطريقة التي تعمل بها قاعدة التعليمات البرمجية الخاصة بك حاليًا من المحتمل جدًا أن تتعطل في الإصدارات المستقبلية من التفاعل. أثناء البحث في https://github.com/mobxjs/mobx-react ، لا أرى أي اقتراح بأنك تستخدم الحالة بهذه الطريقة. في الواقع ، يبدو أنهم يريدون منك استخدام الخصائص.
بمراجعة https://mobx.js.org/getting-started.html و googling لـ "mobx reaction state" ، أخفق في العثور على أي وثائق تقترح استخدام mobx بالطريقة التي تفعل بها ذلك.
من المفترض أن تنقل DT روح المكتبة الأساسية في أحسن الأحوال والتنفيذ الفعلي في أسوأ الأحوال ومن الواضح أن الشراء في عنصر التفاعل والتمديد يعني احترام العقد الضمني.
لست متأكدًا مما أقترح عليك فعله. بعض الخيارات التي يمكنني التفكير فيها:
state
هو البحث عن React.Component
واستبداله بـ MyComponent
وتحديد MyComponent
ليكون فئة فرعية من React.Component
بدون قيود القراءة فقط.this.state
واستخدام المتغيرات على React.Component
الفعلي. قد يكون هذا مؤلمًا بعض الشيء ولكن على الأقل سيتمكن الأشخاص الجدد في مشروعك من رؤية الأنماط في قاعدة التعليمات البرمجية الخاصة بك كما هو موصوف على الإنترنت.state
في كل مكون إذا كنت تريد الاستمرار في القيام بذلك على غرار ما تفعله.this.state
واستبداله بـ this.somethingElse
والإعلان يدويًا.إذا كان هذا هو مشروعي ، فمن المحتمل أن أفعل رقم 2 ، على الرغم من أنني لا أعرف ما يكفي عن mobx لأعرفه على وجه اليقين.
آسف لم أستطع الاتفاق معك (لا يعني أن الآخرين لن يتفقوا معك). حاولت أن أجد سببًا للعودة عن هذا الجزء ولكن لا يمكنني الانضمام إلى هذا الجزء في هذا الوقت.
سأذكر مرة أخرى استراتيجيتنا ، وهي تطبيق مخصص لملاحظات RxJs لدفع تغييرات حالة React وتقديمها والتي تشبه إلى حد كبير نمط mobx. نستخدم الإجراءات لتلقي المدخلات من طبقة العرض (React). الإجراءات مرادفة للدالة التي تستهلك المدخلات وتنتج عنصرًا يمكن ملاحظته ، مما سيؤدي بعد ذلك إلى دفع مراقبات الحالة الأخرى. يسمح هذا النمط للحالة بالبقاء غير قابلة للتغيير من منظور طبقة React ، حيث إنك تقوم فقط بالاستعلام عن القيم التي يمكن ملاحظتها وتنفيذ إجراءات الحالة. داخليًا ، قد "تتحول" دولتك إلى نفسها نتيجة للإجراءات ، حيث لا توجد قيود للقراءة فقط على الحالة الداخلية.
لا أستطيع أن أهدأ. لديّ المشروع قيد الإنتاج وأحتاج إلى قضاء قدر كبير من الوقت مع الفرق ، وهذا يعني المال منذ هذا التغيير.
وما هو السبب؟ هل هذا التغيير يعكس الواقع في رد الفعل؟ لا ، فهو يضيف القيود والسلوك غير الموجود في رد الفعل ، والقيود التي تمت إضافتها بطريقة ما لمجرد اعتقاده أن هذا صحيح.
ما هو الهدف من مشروع DT؟ لوصف مكتبات JS بأنها دقيقة بقدر الإمكان ، أو وصف رؤيتنا لطريقة الاستخدام الصحيح لتلك المكتبات؟ وفقًا لاسم "بالتأكيد مكتوب" ، فهو الأول. لذلك ، إذا لم يكن هذا التقييد موجودًا في مكتبة JS الأصلية ، فيجب ألا يكون موجودًا في DT أيضًا. هذه وجهة نظري. أين أنا مخطئ في هذه النقطة؟
أتفهم أنك محبط ، ومع ذلك ، فهذه هي الطريقة التي كان من المفترض أن يتم استخدام رد الفعل من خلال قراءة المستندات. بالكاد أرى كيف يجب أن نجعل DT أقل تحديدًا لأن فريقك أساء استخدام المكتبة وانتهاك العقد الضمني.
أرني أونصة واحدة من الوثائق التي وضعها فريق التفاعل والتي تقترح أن الحالة يجب أن تكون قابلة للتغيير بشكل مباشر وسأغير الكود على الفور.
https://facebook.github.io/react/docs/react-component.html#state
لا تقم أبدًا بتغيير this.state مباشرةً ، لأن استدعاء setState () بعد ذلك قد يحل محل الطفرة التي أجريتها. تعامل مع هذه الحالة كما لو كانت غير قابلة للتغيير.
يبدو من الواضح تمامًا أن التفاعل يعتبر this.state
غير قابل للتغيير. لا تعتبر React أن الخصائص _ الخاصة بـ this.state
غير قابلة للتغيير (وهو افتراض الإعادة). أنت حر في القيام بما يلي:
this.state.user.name = "foo";
في رد فعل اصطلاحي.
أفضّل كتابة واجهة برمجة التطبيقات بدقة (وهو ما يعني في هذه الحالة Readonly
) والتعبير عن جميع الثوابت التي ينص عليها فريق التفاعل.
ericanderson آسف لقد لاحظت هذا للتو. FWIW أعتقد أن التغيير معقول وأن الأدوات ستلحق بالركب. هل سمعت أنهم يفكرون في إهمال الحمولة الزائدة setState
التي تأخذ شيئًا ما؟ المستقبل هو نمط التخفيض setState
بكل الحسابات.
amoreland لا أوافق. حسب: https://facebook.github.io/react/docs/state-and-lifecycle.html#do -not-edit-state-مباشرة
لا تعدل الحالة مباشرة
على سبيل المثال ، لن يؤدي هذا إلى إعادة تصيير أحد المكونات:
// Wrong this.state.comment = 'Hello';
بدلاً من ذلك ، استخدم setState ():
// Correct this.setState({comment: 'Hello'});
المكان الوحيد حيث يمكنك تعيين this.state هو المنشئ.
johnnyreilly لم أفعل. ذلك مثير للاهتمام. مصدر؟
تمت تغطيتها في أحد المحادثات في مؤتمر رد الفعل الأخير. إنه متاح على موقع يوتيوب. ربما كان حديث لين كلارك. إحدى المحادثات الأولى في اليوم الأول - تغطي التغييرات القادمة للتفاعل مع الإصدار 16. الألياف وما إلى ذلك
https://www.reddit.com/r/reactjs/comments/5zqgsb/react_fiber_functional_setstate/ المذكورة هنا من قبلgaeron
آسف gaearon قصدته
السبب وراء إجراء mobx لتغييرات الحالة ، هو أن الملاحظات تقود تحديثات React ، بدلاً من _ استبدال_ الحالة تمامًا ، تصبح الحالة محركًا يقود العرض. لذلك من خلال القيام بشيء مثل this.state.updating = true;
، فأنت تقوم في الواقع بعمل مكافئ لاستبدال الحالة ، ولكن بدلاً من ذلك تكون الحالة ذكية بما يكفي لتشغيل عرض جديد عن طريق إخطار المكون بأن الحالة قد تم تغييرها عن محتواها السابق. أوافق على أن هذا ليس استخدامًا _ تقليديًا_ لتفاعل React ، ولكنه استخدام أكثر شمولاً وأعلى مستوى لـ React. أود أن أزعم أن استخدام React التقليدي مفيد فقط للمشاريع الصغيرة التي تحتوي على عدد قليل من المكونات. عندما ينتهي بك الأمر بمئات من المكونات لكل منها العشرات من محركات الطفرات التفاعلية ، لم يعد بإمكانك استخدام تعديلات حالة React التقليدية (على سبيل المثال ، setState) بشكل موثوق به ويجب أن تستمتع بالتغييرات المعمارية التي تتضمن _smart_ state (وهو ما يفعله mobx أساسًا ).
بعد قولي هذا ، أفهم سبب استيائه ، لأن تغييرات الكتابة تؤثر على استخدام أكثر تقدمًا لنظام React. إن تخصيصات الحالة التي يمكن ملاحظتها ليست حالة _mutating_ تقنيًا ، ولكنها تستدعي أحداثًا يمكن ملاحظتها لقيمة RHS. يحدث فقط أن التركيب اللغوي الذي اختاره mobx لإصدار هذه الأحداث التي يمكن ملاحظتها يتعارض مع النية الصريحة لحالة React الثابتة.
Iezious إذا كنت بحاجة إلى حل سريع لهذا النوع من المشاكل ، يمكنك أن تفلت منه من خلال زيادة كتابة React وإعادة تشكيل مكوناتك لاستخدام امتداد إلى React.Component
type defs.
import * as React from 'react';
declare module 'react' {
class MutableStateComponent<P, S> extends React.Component<P, S> {
state: S;
}
}
(React as any).MutableStateComponent = React.Component;
والآن يمكنك فقط إنشاء مكونات حالة قابلة للتغيير تمامًا مثل المكونات العادية ، باستثناء أن العضو state
لم يعد محددًا على أنه readonly
.
export class MyComponent extends React.MutableStateComponent<MyProps, MyState> {
// this.state.name is writable
}
patsissons نعم ، هذا هو السبب بالضبط.
أنا لا أقوم بتغيير الحالة ، فأنا أستخدم موبكس المرصدات ، والتي تستدعي setState بالنسبة لي ، وأنا أفعل ذلك لأن كود مشروعي الضخم يبدو أكثر وضوحًا ومفهومًا.
أعلم أنه يمكنني إنشاء المكون الخاص بي ، ويمكنني أيضًا في خادم npm إنشاء برنامج نصي سيعيد هذا التغيير دائمًا لشركتنا. يمكنني استخدام الاختراق مثل "this.state.state.updated" والكثير من الاختراقات الأخرى.
أريد فقط أن أقول ، أن هذا التغيير يؤثر على استخدام أنماط يمكن ملاحظتها مثل mobx ، والتي تتبع في الواقع طريقة التفاعل ، ولكن الآن ، نظرًا لأن هذا التغيير لا يمكن تجميعه ويحتاج إلى بعض الاختراقات والحلول للعمل. ولهذا أعتقد أن هذا التغيير ليس صحيحًا.
ربما بدلاً من MutableStateComponent
الذي اقترحناه ، نطلق عليه بدلاً من ذلك ObservableComponent
وهو أكثر توافقًا مع نمط التفاعل القابل للملاحظة.
إذا قمت بإسقاط Readonly
، فإن الأشخاص الذين يستخدمون أنواع التفاعل مع رد الفعل المنتظم (و / أو أي عدد من أنظمة إدارة الحالة الأخرى بخلاف mobx) يتعرضون للأخطاء. لا أستخدم mobx في مشروعي الضخم وأنا أقدر أخطاء المترجم عندما يقوم شخص ما بخطأ إملائي ويستخدم عن طريق الخطأ this.state.foo = bar
.
إذا كانت هناك مقايضة لا مفر منها بين التفاعل القياسي واستخدام التفاعل غير القياسي ، فيجب أن تميل أنواع التفاعل القياسية إلى الأول.
علاوة على ذلك ، إذا كنت تستخدم mobx بالطريقة الاصطلاحية ، فهذه ليست مشكلة.
إذا قمت بإسقاط Readonly ، فإن الأشخاص الذين يستخدمون أنواع التفاعل مع رد فعل منتظم (و / أو أي عدد من أنظمة إدارة الحالة الأخرى بخلاف mobx) يتعرضون للأخطاء. لا أستخدم mobx في مشروعي الضخم وأنا أقدر أخطاء المترجم عندما يقوم شخص ما بخطأ إملائي ويستخدم هذا الخطأ.
لذا مرة أخرى - إنك تُعلم لكتابة المدونة
هذا المشروع لا يتعلق بتدريس كتابة الكود ، هذا المشروع هو لوصف الوظائف الحالية لمكتبات JS. القيد الذي تمت مناقشته غير موجود في المكتبة الأصلية ويجب حذفه.
هذا كل شئ.
تضمين التغريدة
إذا كنت بحاجة إلى حل سريع لهذا النوع من المشاكل ، يمكنك أن تفلت منه نوعًا ما عن طريق زيادة كتابة React وإعادة تشكيل مكوناتك لاستخدام امتداد إلى React.Component type defs.
ليس صحيحا. في عالم المؤسسات ، حيث أنا ، لا توجد "حلول سريعة". عندما يتغير شيء ما في SDK ، يجب أن يكون متوافقًا مع الإصدارات السابقة ، أو يستغرق الأمر سنوات. لا توجد إصلاحات سريعة في 2M + سطر من مشروع الكود. لقد مرت أسابيع من التغييرات ، والاختبارات ، واختبار A / B prod ، وطرح عدد كبير من الأشخاص. يكلف نقودًا حقيقية. وكل هذا الجهد الهائل لمجرد أن شخصًا ما أضاف تغييرًا غير متوافق مع الإصدارات السابقة والذي لا يوجد في المكتبة الحقيقية؟
لماذا تعتقد أن ForceUpdate لا يزال موجودًا في رد الفعل؟ يتحدثون عن الأسلوب الصحيح ، لكنهم يقومون بالتغييرات لمنع طرق الاستخدام الأخرى. لماذا ا؟ نظرًا لأنها شركة كبيرة وهم يعلمون أن المكتبات يجب أن تكون متوافقة مع الإصدارات السابقة.
كتب ericanderson ذلك
this.state.state.value = 1
ليس شرعيًا أيضًا من وجهة نظره. في المرة القادمة سيحصل على الأداة من TS ويضيف القيد الذي سيمنع هذا الرمز. أو اجعل فئة المكون النهائية ، أو أي شيء آخر لمجرد "أنه أسلوب صحيح ويمنع الناس من ارتكاب الأخطاء".
منع الأشخاص من التخفيف - إنها مهمة FB ، إذا أرادوا القيام بذلك ، فيمكنهم بسهولة إضافة وكيل وعدم السماح بطفرة الحالة. الغرض من DT هو إضافة الأوصاف ، ولا شيء غير ذلك.
تضمين التغريدة
أعتقد أن الهدف هو أن فريق React لا يمكنه جعل الحالة غير قابلة للتغيير باستخدام JavaScript ، ولكن إذا أمكنهم فعل ذلك. من ناحية أخرى ، يمكن أن تجعل TypeScript الحالة غير قابلة للتغيير ، ولهذا السبب تم إجراء هذا التغيير على تعريفات النوع. كان قصد فريق React مطلقًا عدم السماح بإجراء تعديلات على أعضاء الدولة بشكل مباشر (كما يتضح من مستنداتهم الرسمية حول استخدام الحالة بشكل صحيح ) ، لكن لم يكن لديهم التركيبات اللغوية لفرض هذا القيد. لم يكن هذا القيد مجهولًا أبدًا ، فقد تم توثيقه جيدًا منذ البداية. بالنسبة لأولئك منا الذين يعملون خارج الاستخدام _ التقليدي_ لـ React ، يجب علينا على الأقل الالتزام بتوصيات الاستخدام الرسمية لـ React. بالنسبة لفريقي ، كان هذا يعني تصميم حل يسمح لنا بتحريك تغييرات الحالة دون تغيير الحالة بشكل مباشر. تم إجراء ذلك على وجه التحديد للتأكد من أننا لن نواجه أي مشكلات مثل هذه (على الرغم من أن هذا التغيير قد أثر علينا قليلاً ، ولكن فقط من خلال التوقيعات الوظيفية وليس التصميم الأساسي).
إذا لم تكن إعادة البناء ممكنة في حالتك ، فإما أن تقوم بإدخال دبوس @types/react
عند 15.0.1
قبل إجراء التغيير ، أو لا تستخدم @types/react
وبدلاً من ذلك احتفظ بالمتغير الخاص بك من اكتب defs وقم ببساطة بتغيير كتابة state
مقابل Component
. لا أعتقد حقًا أنك ستنجح في إقناع أي شخص بالعودة إلى التغيير.
forceUpdate
موجود لأنه موثق كمسار الكود الموصى به لقيادة العرض عند تعديل الحالة الهيكلية الداخلية (أو عندما يستخدم render()
بيانات خارج الحالة قابلة للتغيير). تم تصميم استخدام forceUpdate
لنمط الاستخدام الذي يستخدمه فريقي بالضبط مع React.
يمكن لفريق React أن يجعل الحالة غير قابلة للتغيير باستخدام JS ، إنه أمر سهل. لكنها غير متوافقة مع الإصدارات السابقة.
مرة أخرى ، هو:
this.state.state.value = 1
شرعي أم لا؟
أعتقد أنه كذلك ، لكن رأيي واضح بالفعل ...
لا أعتقد أن المحادثة حول القابلية للتغيير / الثبات ذات صلة _ حتى الآن_. من الواضح أن الخطأ في مترجم TS (بخصوص Readonly
) مع هذا التغيير يجعل المكونات العامة مستحيلة تمامًا للاستخدام ، مما يكسر الكثير من الكود الموجود. بالتأكيد هذه حالة استخدام صالحة ومقبولة عالميًا وهي سبب كاف للتراجع عنها في الوقت الحالي ؟؟؟
interface test1 {
num: number;
}
function add<T extends test1>(initial: T, add: number) {
var copy: Readonly<T> = initial;
//ERROR HERE: [ts] Operator '+' cannot be applied to types 'T["num"]' and 'number'.
return copy.num + add;
}
هل يعرف أي شخص ما إذا كانت هناك مشكلة مفتوحة مع فريق Typescript حول هذا الأمر؟ لا يمكنني العثور على المشكلة ذات الصلة على تعقبهم.
caesay راجع Microsoft / TypeScript # 15501
يجب أن أبدأ الحالة في المُنشئ ، لكن يُظهر tslint "الحالة للقراءة فقط" ....
constructor(props) {
super(props);
this.state = {
value: props.defaultValue,
};
}
كيف يمكنني إصلاح ذلك...............
استخدم setState
لا يعمل setState في المُنشئ
أو ضع في الاعتبار componentWillMount w / setState
شكرا
أهلا،
قرأت الموضوع بالكامل ولكن ليس من الواضح بالنسبة لي ما إذا كانت هناك خطط للتعامل مع سيناريو @ alanwei0 ؟
أوافق تمامًا على أنه من المنطقي أن يكون لديك state
كـ ReadOnly
. ومع ذلك ، فإن عدم القدرة على ضبط الحالة الأولية في المُنشئ يعقد الأمور بعض الشيء لأن render
يُستدعى قبل أن يتم componentDidMount
.
pawelpabich استخدام this.state = {
في المنشئ ليس مشكلة. يمكنك تعيين متغيرات readonly
في المنشئ ، و Readonly<T>
لا يمنع التعيين (على الإطلاق!).
interface TInterface {
test: string;
}
class TClass {
readonly blah: Readonly<TInterface>;
constructor() {
this.blah = { test: "constructor" };
}
fn = () => {
this.blah = { test: "fn" };
}
}
الخطأ الوحيد هنا سيكون داخل fn
- ليس بسبب Readonly<T>
، ولكن بسبب readonly
الكلمة الأساسية. في الواقع ، لا تستخدم أحدث نسخة من الكتابات حتى الكلمة الأساسية readonly
، لذلك يمكنك في الواقع تعيين الحالة في أي مكان ، فقط لا تغير الخصائص داخل الحالة.
كانت المشكلة التي كنا نتحدث عنها هنا هي وجود خلل في المترجم المنسوخ الذي تسبب في فقدان خصائص الحالة لأنواعها في المكونات الموروثة. أعتقد أنه تم إصلاح هذا منذ ذلك الحين ، وإذا كان الأمر كذلك ، فيمكن إغلاق هذه المشكلة.
caesay آسف ، اعتقدت أن هذا هو الحال الذي نتحدث عنه هنا. مشكلتي هي أنني لا أستطيع تعيين الحالة في الفئة الأساسية. أنا مشترك في TS 2.4.1. هل لديك أي فرصة معرّف المشكلة حتى أتمكن من التحقق من ذلك؟
يمكنك دائمًا استدعاء setState (في componentWillMount).
pawelpabich مرة أخرى ، هذه ليست مشكلة :) لا يمكنك تعيين الحالة من الفئة الأساسية عن قصد . كيف استطعت؟ لا تعرف عقد الخاصية الذي يستخدمه المكون المشتق.
interface BaseCompState {
baseState1?: string;
}
class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
constructor(props) {
super(props);
this.state = {
baseState1: "fromBase",
};
}
}
interface TopCompState extends BaseCompState {
topState1?: string;
}
class TopComp extends BaseComp<TopCompState> {
constructor(props) {
super(props);
this.state = {
baseState1: "fromTop",
topState1: "fromTop",
};
}
}
هذا مثال بسيط لمكوِّن مشتق (الدعائم محذوفة ، لكن الفكرة نفسها). من الواضح أن this.state =
في الفئة الأساسية لا يعمل ، لأنه لا يعرف ما هو TState
. علاوة على ذلك ، إذا نجح الأمر ، فسيكون مجرد الإفراط في كتابة الحالة التي حددها الوالد. ستكون الحالة النهائية { baseState1: "fronBase" }
. ماذا حدث لممتلكات TopState؟
إذا كنت مقتنعًا تمامًا أنك بحاجة إلى التعامل مع الحالة في المكون الأساسي الخاص بك ، فيمكنك تمرير الحالة من المكون المشتق إلى مُنشئ المكون الأساسي (مثل TState
حتى تتمكن من تعيينه) - قد يبدو ذلك مثل هذه:
interface BaseCompState {
baseState1?: string;
}
class BaseComp<TState extends BaseCompState> extends React.Component<any, TState> {
constructor(props, state: TState) {
super(props);
this.state = Object.assign({
baseState1: "fromTop",
}, state);
}
}
interface TopCompState extends BaseCompState {
topState1?: string;
}
class TopComp extends BaseComp<TopCompState> {
constructor(props) {
super(props, {
topState1: "fromTop",
});
}
}
أو حتى أبسط من ذلك ، يمكنك الاتصال بـ this.setState(
من داخل المكون الأساسي الخاص بك (نعم ، يمكنك القيام بذلك في المُنشئ!)
لا توجد مشكلة هنا.
caesay أوافق تمامًا على أنه إذا لم تكن هناك قيود ، فلن يكون التعيين منطقيًا. لكن ما زال اتباع التعليمات البرمجية يولد أخطاء في الترجمة على الرغم من أن المحول البرمجي لديه جميع المعلومات المطلوبة للتحقق من صحة الكود.
import * as React from "react";
/* tslint:disable:max-classes-per-file*/
interface BaseProps {
baseProp: string;
}
interface BaseState {
baseState: string;
}
class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
constructor(props) {
super(props);
this.state = {
baseState: props.baseProp
};
}
render() {
return <div>{this.state.baseState}</div>;
}
}
interface DerivedProps extends BaseProps {
derivedProp: string;
}
interface DerivedState extends BaseState {
derivedState: string;
}
export class Derived extends Base<DerivedProps, DerivedState> {
constructor(props) {
super(props);
this.state = {
derivedState: props.derivedProp
};
}
render() {
return <div>{this.state.derivedState}</div>;
}
}
أخطاء
webpack: Compiled successfully.
ERROR at Test.tsx(17,9):
TS2322: Type '{ baseState: any; }' is not assignable to type 'Readonly<TState>'.
ERROR at Test.tsx(39,9):
TS2322: Type '{ derivedState: any; }' is not assignable to type 'Readonly<DerivedState>'.
Property 'baseState' is missing in type '{ derivedState: any; }'.
Version: typescript 2.4.1
أولا. لم تتم كتابة الدعائم في القاعدة في المُنشئ. وبالتالي فإن props.baseProp
هو any
، وهو غير قابل للتخصيص!
ثانيًا ، تحتوي أدواتك في Derived
على المشكلة نفسها وتفتقد baseState
. الذي بالطبع لن يعمل ، بغض النظر عن Readonly
TProps extends BaseProps
مما يعني أن TProps
لديه على الأقل نفس الأعضاء الذين BaseProps
. فكيف لم يتم تعريف ذلك؟ أنا أفهم أن المترجم قد لا يكون قادرًا على الاستدلال عليه ولكن القول بأن ذلك لم يتم تعريفه لا يبدو صحيحًا. يمكن تطبيق نفس التفكير على Derived
.
caesay setState
في المُنشئ ليس حلاً موثوقًا به لأن هذه الطريقة غير متزامنة ولا يزال بإمكانك الوصول إلى render
بدون تعيين الحالة الأولية.
الحل الوحيد الموثوق الذي يمكنني رؤيته هو ضبط الحالة بأكملها في الفئات المشتقة. هذا له عيب واضح وهو:
المثال الذي عرضته أعلاه سيعمل في C # لذا سيكون من الجيد أن يعمل في TypeScript.
setState
في componentWillMount
. قاعدتك لا تعرف ما يجب أن يكون في الحالة لطفلها ، لذلك لا يمكنها الحصول على this.state
في تكوين آمن. ومع ذلك ، يمكن للفئة الفرعية الخاصة بك استدعاء componentWillMount
للوالد ثم تعيين الحالة التي تعتقد أنها بحاجة إليها أيضًا.this.state
بكائن لا يتطابق مع النوع المتوقع.محرر ، ليعكس أنني كنت مخطئًا بشأن setState في المُنشئ ولإضافة backticks لسهولة القراءة.
ericanderson لا أعتقد أننا نحرز أي تقدم هنا. لقد عرضت لك مثالاً وسأكون ممتنًا لو تمكنا من التركيز عليه. وإلا فإنه من الصعب إجراء مناقشة.
Re setState
ليس آمنًا للاستخدام في المُنشئ. لا يتسبب في حدوث خطأ ولكنه لن يقوم بتعيين الحالة قبل حدوث التصيير. لدي شفرة تعطلت بسبب ذلك ومستندات React واضحة جدًا ولا يجب استخدامها هناك.
pawelpabich لا ، هذا ليس المكان المناسب لهذه الحجة. أنت مخطئ بشكل أساسي في فهمك للغة. في المثال الذي قدمته ، أنت غير راضٍ عن عقد "الولاية" في أيٍّ من مهامك للدولة.
على سبيل المثال ، عندما تفعل
this.state = { baseState: props.baseProp };
// now the state is exactly { baseState: props.baseProp }
الولاية هي بالضبط { baseState: props.baseProp }
وهذا لا يفي بمتطلبات TProps extends BaseProps
(لأننا لا نعرف ما هي TProps! يمكن أن تحتوي على أي خصائص فيها).
بعد ذلك ، تقوم بمهمة _ منفصلة _.
this.state = { derivedState: props.derivedProp };
// now the state is exactly { derivedState: props.derivedProp }
الولاية الآن هي بالضبط { derivedState: props.derivedProp }
(لقد قمت بالكتابة فوق تعيين الحالة الأساسية الخاص بك !!) وهذا لا يرضي DerivedState OR BaseProps.
أنت مضلل تمامًا في التفكير في أن هذا يجب أن ينجح. إذا كانت لديك مشكلة في كيفية عمل التخصيص الأساسي المتغير ، فاستعن بمصممي اللغة في إصدار جديد واحصل على إسقاط هناك حتى نتوقف عن تلقي الإشعارات هنا من فضلك.
كملاحظة جانبية - أنت تتجاوز أيضًا طريقة الأساس render()
، مما يعني أن المكون الأساسي الخاص بك لن يكون قادرًا على تقديم أي شيء. إذا كنت مقتنعًا بأن هذا هو ما تريده ، فيمكنك إضافة عضو محمي getBaseState()
واستدعاء هذا من المُنشئ المشتق عند تعيين الحالة (حتى لا تضطر إلى تكرار منطق الحالة الأساسية). لكن ما أعتقد أنك تريده حقًا هو عدم استخدام المكونات المشتقة على الإطلاق. حاول إعادة الهيكلة لاستخدام التركيب (حيث يكون لديك كائن واحد يحتوي على كائنات فرعية متعددة). أعتقد أنك ستجده سيصبح أكثر نظافة.
لا أريد الابتعاد عن القراءة لإنشاء مشروع جديد لمجرد مناقشة هذا معك ، ولكن للأسف ...
سأقف مصححًا حول setState
() في المُنشئ ، لكن هذا لا يغير شعوري حيال استخدامه في componentWillMount
.
مثال عملي لكيفية القيام بذلك:
https://github.com/ericanderson/set-state-example
على وجه التحديد ، index.tsx:
import * as React from "react";
import * as ReactDOM from "react-dom";
/* tslint:disable:max-classes-per-file*/
interface BaseProps {
baseProp: string;
}
interface BaseState {
baseState: string;
}
class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
public componentWillMount() {
this.setState({
baseState: this.props.baseProp,
});
}
public render() {
return (
<p>
<code>this.state.baseState: </code>
{this.state.baseState}
</p>
);
}
}
interface DerivedProps extends BaseProps {
derivedProp: string;
}
interface DerivedState extends BaseState {
derivedState: string;
}
export class Derived extends Base<DerivedProps, DerivedState> {
public componentWillMount() {
super.componentWillMount();
this.setState({
derivedState: this.props.derivedProp,
});
}
public render() {
return (
<div>
<p>
<code>this.state.derivedState: </code>
{this.state.derivedState}
</p>
{super.render()}
</div>
);
}
}
ReactDOM.render(<Derived derivedProp="its derived" baseProp="its basic" />, document.getElementById("main"));
pawelpabich إذا كنت تريد تنفيذ مكون متعدد الأشكال مع حالة أولية ، فستحتاج إلى جعل المكون الأساسي مجردة وإنشاء دالة مجردة getInitialState()
(أو ذات موضوع مشابه) لتنفيذه في الفئة المشتقة. ما عليك سوى تعيين الحالة مرة واحدة ، إما في المُنشئ أو باستخدام setState
كما أظهرericanderson .
فيما يلي مثالك الذي تم تحويله إلى حل متعدد الأشكال بالكامل ، مع فصل كامل للمخاوف فيما يتعلق ببناء الدولة:
interface BaseProps {
baseProp: string;
}
interface BaseState {
baseState: string;
}
abstract class Base<TProps extends BaseProps, TState extends BaseState> extends React.Component<TProps, TState> {
constructor(props: TProps) {
super(props);
this.state = this.getInitialState();
}
protected abstract getInitialState(): TState;
protected getBaseState() {
return this.props.baseProp;
}
render() {
return <div>{this.state.baseState}</div>;
}
}
interface DerivedProps extends BaseProps {
derivedProp: string;
}
interface DerivedState extends BaseState {
derivedState: string;
}
export class Derived extends Base<DerivedProps, DerivedState> {
getInitialState(): DerivedState {
return {
baseState: this.getBaseState(),
derivedState: this.props.derivedProp,
};
}
render() {
return <div>{this.state.derivedState}</div>;
}
}
تضمين التغريدة
caesay أعترف أنني كنت مخطئًا ولسبب ما لم أر أن التعيينات ستتجاوز بعضها البعض. ومع ذلك ، فإن استخدام CAPS و !
لم يساعدني في الخروج من الحفرة.
ركز patsissons و ericanderson على المشكلة والآن لدينا حل يمكن للآخرين استخدامه.
pawelpabich أوافق على أن سلوكياتي كانت أقل من احترافية - لكن من المفهوم لذلك بالنظر إلى أنني قدمت لك العديد من التفسيرات والعينات وما إلى ذلك ، واخترت عدم الاستماع إلي.
عندها سيكون الأمر مجرد كتابة مفرطة للحالة التي حددها الوالد.
[_إذا كنت تريد_] معالجة الحالة في المكون الأساسي ، فيمكنك تمرير الحالة من المكون المشتق إلى مُنشئ المكون الأساسي
[_ إذا كنت تريد معالجة الحالة في المكون المشتق الخاص بك_] يمكنك إضافة عضو محمي getBaseState () واستدعاء هذا من المُنشئ المشتق عند تعيين الحالة.
ما فعله patsissons هو أخذ التعليقات التي سبق ذكرها هنا وتقديم عينة رمز - وهو ما لا ينبغي أن يكون ضروريًا. هذا ليس تدفقًا مكدسًا ، ولا نقدم غالبًا عينات أكواد جاهزة هناك أيضًا.
أنا جديد في الرد والنص ، ربما لا أعرف شيئًا ، ولكن على الرغم من أن التطبيق يجمع دون أي خطأ أو تحذير أو تلميح ، أحصل على خطأ في وقت التشغيل. أدناه هو مثال للمكون. أنسب الخطأ إلى Readonly
state. إذا كان التطبيق يعمل قبل تغيير Readonly
، فبعد هذا التغيير توقف عن العمل ولا يعطي أخطاء وقت التجميع.
import * as React from 'react';
export default class HomePage extends React.Component<any, Map<string, string>> {
public componentWillMount() {
const map = new Map<string, string>();
map.set('aKey', 'aValue');
this.setState(map);
}
public render() {
return (
<div className="home">
<div className="greeting">
Home page: {this.state.get('aKey')} // <-- I get an error here
</div>
</div>
);
}
}
الخطأ:
homePage.tsx:12 Uncaught TypeError: this.state.get is not a function
at HomePage.render (homePage.tsx:12)
at eval (ReactCompositeComponent.js:793)
at measureLifeCyclePerf (ReactCompositeComponent.js:73)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (
يجب أن تكون الحالة دائمًا عبارة عن كائن ذي مفتاح عادي afaik ، لذلك بدلاً من ذلك قم بتعريف الحالة
كشيء مثل: { values: Map <string, string> }
وقراءته
this.state.values.get('aKey')
المرجع vr 29 سبتمبر. 2017 09:01 schreef Janusz Białobrzewski <
[email protected]>:
أنا جديد في الرد والطباعة ، ربما لا أعرف شيئًا ، لكن حتى
على الرغم من أن التطبيق يجمع دون أي خطأ أو تحذير أو تلميح ، إلا أنني أحصل على وقت تشغيل
خطأ. أدناه هو مثال للمكون. أنسب الخطأ للقراءة فقط
حالة. إذا كان التطبيق يعمل قبل تغيير Readonly ، ثم بعد ذلك
تغييره توقف عن العمل ولا يعطي أخطاء وقت الترجمة.استيراد * كرد فعل من "رد فعل" ؛
يقوم HomePage بتصدير الفئة الافتراضية لتوسيع React.Component> { public componentWillMount () {
خريطة const = خريطة جديدة() ؛
map.set ('aKey'، 'aValue')؛
this.setState (خريطة) ؛
}عرض عام () {
return ( <div className="home"> <div className="greeting"> Home page: {this.state.get('aKey')} // <-- I get an error here </div> </div> );
}
}الخطأ:
الصفحة الرئيسية. tsx: 12 خطأ في النوع غير معلوم: this.state.get ليست دالة
في HomePage.render (homePage.tsx: 12)
في EVAL (ReactCompositeComponent.js: 793)
at scaleLifeCyclePerf (ReactCompositeComponent.js: 73)
في ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (-
أنت تتلقى هذا لأنه تم ذكرك.
قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/14250#issuecomment-333047367 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/ABvGhM5hDyRNyUeZuIiGeTZk1N-rfuA4ks5snJW5gaJpZM4LuDWV
.
شكرًا ، ولكن يبدو أنه جهد لا طائل منه لإعلان الحالة على أنها Readonly<S>
، لأن أعضائها المتداخلين لا يتأثرون بالقراءة فقط.
من المحتمل أن يتم تطبيق Readonly
يومًا ما بشكل متكرر ، ولكن في الوقت الحالي ، عليك التأكد من أنك تتعامل معه بشكل صحيح. في حالتك ، يجب أن تعلن حقًا عن ReadonlyMap
أو
interface State {
readonly [key: string]: string;
}
أو متداخل:
interface State {
map: { readonly [key: string]: string };
}
يمكننا استخدامه للقراءة العميقة فقط:
export type DeepReadonly<T> =
T extends Array<any> ?
ReadonlyArray<T[0]> :
T extends Date ?
T :
T extends Function ?
T :
T extends object ?
{ readonly [P in keyof T]: DeepReadonly<T[P]> } :
T;
export type Writable<T> =
T extends ReadonlyArray<any> ?
Array<WritableObject<T[0]>> :
T extends Array<any> ?
Array<WritableObject<T[0]>> :
WritableObject<T>;
type WritableObject<T> =
T extends Date ?
T :
T extends Function ?
T :
T extends object ?
{ -readonly [P in keyof T]: Writable<T[P]> } :
T;
التعليق الأكثر فائدة
أعتقد أن المشكلة 3 مطروحة للنقاش.
أنت محق في أنه يمكنك _تقنيًا_ عمل المثال أعلاه في React ، لكنني سأجادل بالتأكيد أن هذه ليست الطريقة التي كان يُقصد من استخدام React بها.
يمكن تقسيم هذا إلى 3 حالات متميزة.
تهيئة عامة
التهيئة على أساس الدعائم
مهمة عشوائية
forceUpdate
نظرًا لأنني أعتقد أنه من الأفضل دفع الأشخاص نحو الشيء "الصحيح" ، يمكنك بسهولة حل هذه المشكلة عن طريق إعادة إعلان
public state
: