कृपया शीर्षक के साथ मेरी सहायता करें और समस्या को बेहतर तरीके से व्यक्त करें।अपरिवर्तनीय डेटा के साथ शुद्ध, जेनेरिक प्रतिक्रिया घटक बनाने के लिए कैसे
मुझे अपने प्रतिक्रिया/रेडक्स आर्किटेक्चर में एक समस्या मिली है जिसे मुझे कई उदाहरण नहीं मिल रहे हैं।
मेरा आवेदन प्रदर्शन के लिए अपरिवर्तनीयता, संदर्भ समानता और PureRenderMixin
पर निर्भर करता है। लेकिन मुझे इस तरह के वास्तुकला के साथ अधिक सामान्य और पुन: प्रयोज्य घटकों को बनाना मुश्किल लगता है।
चलें कहते हैं कि मैं एक सामान्य ListView
इस तरह है:
const ListView = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
items: arrayOf(shape({
icon: string.isRequired,
title: string.isRequired,
description: string.isRequired,
})).isRequired,
},
render() {
return (
<ul>
{this.props.items.map((item, idx) => (
<li key={idx}>
<img src={item.icon} />
<h3>{item.title}</h3>
<p>{item.description}</p>
</li>
)}
</ul>
);
},
});
और फिर मैं एक redux की दुकान से उपयोगकर्ताओं को प्रदर्शित करने के लिए सूची दृश्य का उपयोग करना चाहते। उनके पास यह संरचना है:
const usersList = [
{ name: 'John Appleseed', age: 18, avatar: 'generic-user.png' },
{ name: 'Kate Example', age: 32, avatar: 'kate.png' },
];
यह मेरे अनुप्रयोगों में अब तक एक बहुत ही सामान्य सेनारियो है। मैं आमतौर पर इसे पसंद प्रस्तुत करना:
<ListView items={usersList.map(user => ({
title: user.name,
icon: user.avatar,
description: `Age: ${user.age}`,
}))} />
समस्या है कि map
संदर्भ समानता टूट जाता है। usersList.map(...)
का नतीजा हमेशा नई सूची वस्तुएं होगी। तो जब भी usersList
पिछले प्रस्तुत करने के बाद से नहीं बदला है, ListView
यह नहीं पता कि यह अभी भी items
-list के बराबर है।
मैं इसके लिए तीन समाधान देख सकता हूं, लेकिन मुझे उन्हें बहुत अच्छा नहीं लगता है।
समाधान 1: एक पैरामीटर के रूप में एक transformItem
समारोह दर्रा और कच्चे वस्तुओं
const ListView = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
items: arrayOf(object).isRequired,
transformItem: func,
},
getDefaultProps() {
return {
transformItem: item => item,
}
},
render() {
return (
<ul>
{this.props.items.map((item, idx) => {
const transformedItem = this.props.transformItem(item);
return (
<li key={idx}>
<img src={transformedItem.icon} />
<h3>{transformedItem.title}</h3>
<p>{transformedItem.description}</p>
</li>
);
})}
</ul>
);
},
});
यह बहुत अच्छी तरह से काम करेंगे की एक सरणी items
रहने दो। मैं तो इस तरह मेरे उपयोगकर्ता सूची प्रदान कर सकते हैं:
<ListView
items={usersList}
transformItem={user => ({
title: user.name,
icon: user.avatar,
description: `Age: ${user.age}`,
})}
/>
और ListView केवल rerender जब usersList
परिवर्तन होगा। लेकिन मैं रास्ते पर प्रोप प्रकार सत्यापन खो दिया।
समाधान 2:
const UsersList = React.createClass({
mixins: [PureRenderMixin],
propTypes: {
items: arrayOf(shape({
name: string.isRequired,
avatar: string.isRequired,
age: number.isRequired,
})),
},
render() {
return (
<ListView
items={this.props.items.map(user => ({
title: user.name,
icon: user.avatar,
description: user.age,
}))}
/>
);
}
});
लेकिन वह एक बहुत अधिक कोड है: एक विशेष घटक है कि ListView
लपेटता बनाओ! बेहतर होगा अगर मैं एक स्टेटलेस घटक का उपयोग कर सकता हूं, लेकिन मुझे पता नहीं चला है कि वे PureRenderMixin
के साथ सामान्य घटकों की तरह काम करते हैं।
const UsersList = ({ users }) => (
<ListView
items={users.map(user => ({
title: user.name,
icon: user.avatar,
description: user.age,
}))}
/>
);
समाधान 3 (राज्यविहीन घटकों उदासी अभी भी प्रतिक्रिया का एक गैर-दस्तावेजी सुविधा है):
const ParameterTransformer = React.createClass({
mixin: [PureRenderMixin],
propTypes: {
component: object.isRequired,
transformers: arrayOf(func).isRequired,
},
render() {
let transformed = {};
this.props.transformers.forEach((transformer, propName) => {
transformed[propName] = transformer(this.props[propName]);
});
return (
<this.props.component
{...this.props}
{...transformed}
>
{this.props.children}
</this.props.component>
);
}
});
एक सामान्य शुद्ध रूपांतरित होने वाले घटक बना सकते हैं और तरह
<ParameterTransformer
component={ListView}
items={usersList}
transformers={{
items: user => ({
title: user.name,
icon: user.avatar,
description: `Age: ${user.age}`,
})
}}
/>
हैं इसका इस्तेमाल ये एकमात्र समाधान हैं, या क्या मुझे कुछ याद आया है?
इनमें से कोई भी समाधान उस घटक के साथ बहुत अच्छी तरह फिट बैठता है जिस पर मैं वर्तमान में काम कर रहा हूं। नंबर एक सबसे अच्छा फिट बैठता है, लेकिन मुझे लगता है कि वह ट्रैक है जिसे मैं आगे बढ़ाना चुनता हूं, फिर मेरे द्वारा बनाए गए सभी प्रकार के जेनेरिक घटकों में इन transform
गुण होना चाहिए। और यह भी एक प्रमुख नकारात्मक पक्ष है कि मैं ऐसे घटकों को बनाते समय प्रतिक्रिया प्रोप प्रकार सत्यापन का उपयोग नहीं कर सकता।
समाधान 2 शायद सबसे अधिक अर्थपूर्ण सही है, कम से कम इस ListView
उदाहरण के लिए। लेकिन मुझे लगता है कि यह बहुत verbose है, और यह भी मेरे असली उपयोग के साथ बहुत अच्छी तरह से फिट नहीं है।
समाधान 3 बहुत जादू और अपठनीय है।
Memoization, हाँ, निश्चित रूप से ! मैं इसके बारे में कैसे सोच नहीं सकता? या, विचार ने मुझे स्ट्रोक किया है, लेकिन मैंने इसके बारे में नहीं सोचा (वास्तव में पहले कभी भी उपयोगी कुछ भी याद रखने की आवश्यकता नहीं है), इसलिए मैंने सोचा कि इसके परिणामस्वरूप सभी पिछली चयनित सूचियों का एक बड़ा कैश होगा। लेकिन cource के, सबसे हाल के परिणाम से अधिक पकड़ने और उसके खिलाफ जांच करने की जरूरत नहीं है। पुस्तकालय में खींचने के बजाय खुद को लागू करने के लिए ज्ञापन संभवतः आसान है। –
निश्चित रूप से, आप इसे स्वयं लागू कर सकते हैं-चयन रद्द करें [कोड की केवल 82 पंक्तियां] (https://github.com/rackt/reselect/blob/master/src/index.js#L82)। –