রিএ্যাক্টের রাজ্যে গভীরভাবে নেস্টেড অবজেক্ট / ভেরিয়েবলগুলি সংশোধন করতে সাধারণত তিনটি পদ্ধতি ব্যবহার করা হয়: ভ্যানিলা জাভাস্ক্রিপ্ট Object.assign
, অপরিবর্তনীয়তা-সহায়ক এবং লোডাশcloneDeep
থেকে ।
এটি অর্জনের জন্য অন্যান্য প্রচুর কম জনপ্রিয় তৃতীয় পক্ষের libs রয়েছে, তবে এই উত্তরে আমি এই তিনটি বিকল্পই কভার করব। এছাড়াও, কিছু অতিরিক্ত ভ্যানিলা জাভাস্ক্রিপ্ট পদ্ধতি রয়েছে যেমন অ্যারে ছড়িয়ে দেওয়ার মতো (উদাহরণস্বরূপ @ এমপেনের উত্তর দেখুন), তবে এগুলি খুব স্বজ্ঞাত, ব্যবহার করা সহজ এবং সমস্ত রাষ্ট্রের কারসাজির পরিস্থিতি পরিচালনা করতে সক্ষম নয়।
যেমন উত্তরগুলিতে শীর্ষে মতামত দেওয়া মন্তব্যে অসংখ্য সময় চিহ্নিত হয়েছিল, যার লেখকরা রাষ্ট্রের সরাসরি পরিবর্তনের প্রস্তাব দেয়: কেবল এটি করবেন না । এটি সর্বব্যাপী প্রতিক্রিয়া বিরোধী-প্যাটার্ন, যা অনিবার্যভাবে অযাচিত পরিণতির দিকে পরিচালিত করবে। সঠিক উপায় শিখুন।
আসুন তিনটি বহুল ব্যবহৃত পদ্ধতির তুলনা করি।
এই স্টেট অবজেক্ট স্ট্রাকচারটি দেওয়া হয়েছে:
state = {
outer: {
inner: 'initial value'
}
}
inner
রাজ্যের বাকি অংশগুলিকে প্রভাবিত না করে আপনি অভ্যন্তরীণ-সর্বাধিক ক্ষেত্রের মান আপডেট করতে নিম্নলিখিত পদ্ধতিগুলি ব্যবহার করতে পারেন ।
1. ভ্যানিলা জাভাস্ক্রিপ্ট এর অবজেক্ট.সেসাইন
const App = () => {
const [outer, setOuter] = React.useState({ inner: 'initial value' })
React.useEffect(() => {
console.log('Before the shallow copying:', outer.inner) // initial value
const newOuter = Object.assign({}, outer, { inner: 'updated value' })
console.log('After the shallow copy is taken, the value in the state is still:', outer.inner) // initial value
setOuter(newOuter)
}, [])
console.log('In render:', outer.inner)
return (
<section>Inner property: <i>{outer.inner}</i></section>
)
}
ReactDOM.render(
<App />,
document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<main id="react"></main>
মনে রাখবেন, অবজেক্ট.সেসাইন একটি গভীর ক্লোনিং করবে না , যেহেতু এটি কেবল সম্পত্তি মানগুলি অনুলিপি করে এবং তাই এটি যা করে তাকে অগভীর অনুলিপি বলা হয় (মন্তব্য দেখুন)।
এটি কাজ করার জন্য, আমাদের কেবল প্রাথমিক প্রকারের বৈশিষ্ট্যগুলি ( outer.inner
) স্ট্রিংস, সংখ্যাগুলি, বুলিয়ানগুলি ম্যানিপুলেট করা উচিত ।
এই উদাহরণস্বরূপ, আমরা একটি নতুন ধ্রুবক ( const newOuter...
) তৈরি করছি , এটি ব্যবহার করে Object.assign
যা একটি খালি বস্তু তৈরি করে ( {}
), এতে অনুলিপি করে outer
বস্তু ( { inner: 'initial value' }
) এবং তারপরে এটির { inner: 'updated value' }
চেয়ে আলাদা কোনও বস্তু অনুলিপি করে।
এইভাবে, শেষ পর্যন্ত নতুন তৈরি newOuter
ধ্রুবকটির সম্পত্তি হ'ল ওভাররাইড { inner: 'updated value' }
হয়ে যাওয়ার পরে একটি মান থাকবে inner
। এটি newOuter
একটি একেবারে নতুন অবজেক্ট, যা রাজ্যে অবস্থার সাথে যুক্ত নয়, সুতরাং এটি প্রয়োজন অনুসারে রূপান্তরিত হতে পারে এবং রাষ্ট্রটি একই থাকবে এবং আপডেট করার আদেশটি সঞ্চালিত হওয়া অবধি পরিবর্তন হবে না।
শেষ অংশটি হ'ল রাজ্যে setOuter()
আসলটি outer
নতুনভাবে তৈরি করা newOuter
বস্তুর সাথে প্রতিস্থাপন করতে (কেবলমাত্র মান পরিবর্তন হবে, সম্পত্তির নামটি পরিবর্তন outer
করবে না)।
এখন কল্পনা করুন আমাদের মতো আরও গভীর অবস্থা রয়েছে state = { outer: { inner: { innerMost: 'initial value' } } }
। আমরা newOuter
অবজেক্টটি তৈরি করার চেষ্টা করতে পারি এবং এটিকে outer
রাজ্য থেকে প্রাপ্ত বিষয়বস্তু দিয়ে পপুলেট করতে পারি , তবে নতুনভাবে তৈরি হওয়া এই বস্তুর প্রতি খুব গভীরভাবে বাসা বেঁধে দেওয়াতে এটির Object.assign
কপি করতে সক্ষম হব না ।innerMost
newOuter
innerMost
আপনি এখনও কপি পারে inner
উপরোক্ত উদাহরণের মতো, কিন্তু এটা এখন একটি বস্তু এবং যেহেতু না একটি আদিম, রেফারেন্স থেকে newOuter.inner
অনুলিপি করা হবে outer.inner
পরিবর্তে, যার মানে আমরা স্থানীয় দিয়ে শেষ হবে newOuter
বস্তুর সরাসরি রাজ্যের বস্তুর বাঁধা ।
এর অর্থ এই যে স্থানীয়ভাবে তৈরি হওয়া পরিবর্তনের ফলে newOuter.inner
সরাসরি outer.inner
বস্তুটির (রাজ্যে) প্রভাব পড়বে , যেহেতু তারা বাস্তবে একই জিনিস (কম্পিউটারের স্মৃতিতে) পরিণত হয়েছিল।
Object.assign
অতএব কেবলমাত্র যদি আপনার অভ্যন্তরীণতম সদস্যদের সাথে আদিম ধরণের মান ধারণ করে তুলনামূলক সহজ এক স্তরের গভীর রাষ্ট্র কাঠামো থাকে তবেই কাজ করবে।
আপনার যদি গভীরতর অবজেক্ট (২ য় স্তর বা তার বেশি) থাকে, যা আপনার আপডেট করা উচিত, ব্যবহার করবেন না Object.assign
। আপনি সরাসরি পরিবর্তনের অবস্থা ঝুঁকিপূর্ণ।
2. লোডাশের ক্লোনডিপ
const App = () => {
const [outer, setOuter] = React.useState({ inner: 'initial value' })
React.useEffect(() => {
console.log('Before the deep cloning:', outer.inner) // initial value
const newOuter = _.cloneDeep(outer) // cloneDeep() is coming from the Lodash lib
newOuter.inner = 'updated value'
console.log('After the deeply cloned object is modified, the value in the state is still:', outer.inner) // initial value
setOuter(newOuter)
}, [])
console.log('In render:', outer.inner)
return (
<section>Inner property: <i>{outer.inner}</i></section>
)
}
ReactDOM.render(
<App />,
document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
<main id="react"></main>
লোডাশের ক্লোনডিপ ব্যবহারের উপায় আরও সহজ। এটি একটি গভীর ক্লোনিং সম্পাদন করে , সুতরাং এটি আপনার পক্ষে একাধিক জটিল রাষ্ট্র যদি বহু স্তরের বস্তু বা অ্যারে ভিতরে থাকে। কেবলমাত্র cloneDeep()
শীর্ষ-স্তরের রাষ্ট্রীয় সম্পত্তি, আপনি যেভাবে খুশি হন ক্লোন করা অংশটি পরিবর্তন করুন এবং setOuter()
এটি আবার রাজ্যে ফিরে আসুন।
3. অপরিবর্তনীয়তা-সহায়ক
const App = () => {
const [outer, setOuter] = React.useState({ inner: 'initial value' })
React.useEffect(() => {
const update = immutabilityHelper
console.log('Before the deep cloning and updating:', outer.inner) // initial value
const newOuter = update(outer, { inner: { $set: 'updated value' } })
console.log('After the cloning and updating, the value in the state is still:', outer.inner) // initial value
setOuter(newOuter)
}, [])
console.log('In render:', outer.inner)
return (
<section>Inner property: <i>{outer.inner}</i></section>
)
}
ReactDOM.render(
<App />,
document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
<script src="https://wzrd.in/standalone/immutability-helper@3.0.0"></script>
<main id="react"></main>
immutability-helper
একে পুরো নতুন স্তরে নিয়ে যায়, এবং এ সম্পর্কে দুর্দান্ত জিনিসটি এটি কেবলমাত্র $set
রাষ্ট্রীয় আইটেমগুলিতেই নয় $push
, এগুলি $splice
, $merge
(ইত্যাদি )গুলিকেও মূল্য দিতে পারে । এখানে উপলব্ধ কমান্ডের একটি তালিকা ।
পার্শ্ব নোট
আবার, মনে রাখবেন, এটি setOuter
কেবলমাত্র রাষ্ট্রের বস্তুর প্রথম স্তরের বৈশিষ্ট্যগুলি ( outer
এই উদাহরণগুলিতে) পরিবর্তন করে, গভীরভাবে বাসা বাঁধে না ( outer.inner
)। এটি যদি অন্যভাবে আচরণ করে, তবে এই প্রশ্নটির অস্তিত্ব থাকবে না।
আপনার প্রকল্পের জন্য কোনটি সঠিক ?
আপনি যদি না চান বা বাহ্যিক নির্ভরতা ব্যবহার করতে না পারেন , এবং একটি সাধারণ রাষ্ট্র কাঠামো রাখেন তবে আঁকড়ে থাকুন Object.assign
।
আপনি যদি একটি বিশাল এবং / অথবা জটিল অবস্থার ব্যবহার করে থাকেন তবে লোডাশ cloneDeep
একটি বুদ্ধিমান পছন্দ।
আপনার যদি উন্নত দক্ষতার প্রয়োজন হয় , অর্থাত্ যদি আপনার রাজ্য কাঠামো জটিল হয় এবং আপনাকে এটিতে সমস্ত ধরণের ক্রিয়াকলাপ সম্পাদন করতে হয় তবে চেষ্টা করুন immutability-helper
, এটি একটি অত্যন্ত উন্নত সরঞ্জাম যা রাষ্ট্রের কারসাজির জন্য ব্যবহার করা যেতে পারে।
... বা, আপনার কি আসলেই এটি করা দরকার?
আপনি যদি প্রতিক্রিয়ার রাজ্যে কোনও জটিল ডেটা ধরে থাকেন তবে এটি পরিচালনা করার অন্যান্য উপায়গুলি নিয়ে ভাবার জন্য এটি বেশ ভাল সময়। সরাসরি প্রতিক্রিয়া উপাদানগুলিতে একটি জটিল রাষ্ট্রীয় অবজেক্টগুলি সেট করা সহজবোধ্য ক্রিয়াকলাপ নয় এবং আমি দৃ strongly়ভাবে বিভিন্ন পদ্ধতির বিষয়ে চিন্তাভাবনা করার পরামর্শ দিই।
সম্ভবত আপনার জটিল ডেটা রেডাক্স স্টোরে রেখে, হ্রাসকারী এবং / অথবা সাগাস ব্যবহার করে এটি সেট করা এবং নির্বাচকগুলি ব্যবহার করে এটি অ্যাক্সেস করা ভাল।