প্রতিক্রিয়াযুক্ত নেস্টেড রাষ্ট্রীয় বৈশিষ্ট্যগুলি কীভাবে আপডেট করবেন


389

আমি নীষ্টিত সম্পত্তি ব্যবহার করে আমার রাজ্যটি সংগঠিত করার চেষ্টা করছি:

this.state = {
   someProperty: {
      flag:true
   }
}

তবে এই জাতীয় অবস্থা আপডেট করে,

this.setState({ someProperty.flag: false });

কাজ করে না এটি কীভাবে সঠিকভাবে করা যায়?


4
আপনার মানে কি কাজ করে না? এটি খুব ভাল প্রশ্ন নয় - কি হয়েছে? কোন ত্রুটি? কি ত্রুটি?
ড্যারেন


16
উত্তরটি প্রতিক্রিয়াতে নেস্টেড স্টেট ব্যবহার করবেন নাএই দুর্দান্ত উত্তর পড়ুন ।
কিওয়ার্টি

4
পরিবর্তে কি ব্যবহার করা উচিত?
জনিস এলমারিস

42
সহজভাবে নেস্টেড স্টেট ব্যবহার না করা আজ যে পরিমাণে ব্যাপকভাবে ব্যবহৃত হচ্ছে তার একটি অগ্রহণযোগ্য উত্তর। এই পরিস্থিতি সামনে আসতে চলেছে এবং বিকাশকারীদের এটির একটি উত্তর প্রয়োজন।
সেরোসায়েস

উত্তর:


454

অর্ডার করার জন্য setStateএকটি নেস্টেড বস্তুর জন্য আপনি পদ্ধতির নিচে অনুসরণ করতে পারেন হিসাবে আমি মনে করি setState নেস্টেড আপডেট হ্যান্ডেল নেই।

var someProperty = {...this.state.someProperty}
someProperty.flag = true;
this.setState({someProperty})

ধারণাটি হ'ল কোনও ডামি অবজেক্ট তৈরি করা যাতে এটিতে ক্রিয়াকলাপ সম্পাদন করা হয় এবং তারপরে উপাদানটির স্থিতিকে আপডেট হওয়া অবজেক্টের সাথে প্রতিস্থাপন করা হয়

এখন, স্প্রেড অপারেটর অবজেক্টটির কেবলমাত্র একটি স্তরের নেস্টেড কপি তৈরি করে। আপনার রাজ্যটি যদি খুব নীস্টযুক্ত থাকে তবে:

this.state = {
   someProperty: {
      someOtherProperty: {
          anotherProperty: {
             flag: true
          }
          ..
      }
      ...
   }
   ...
}

আপনি প্রতিটি স্তরের মতো স্প্রেড অপারেটর ব্যবহার করে স্টেট স্টেট করতে পারেন

this.setState(prevState => ({
    ...prevState,
    someProperty: {
        ...prevState.someProperty,
        someOtherProperty: {
            ...prevState.someProperty.someOtherProperty, 
            anotherProperty: {
               ...prevState.someProperty.someOtherProperty.anotherProperty,
               flag: false
            }
        }
    }
}))

তবে উপরের সিনট্যাক্সটি প্রতিটি কুরুচিপূর্ণ হিসাবে রাজ্য আরও বেশি ঘৃণিত হয়ে ওঠে এবং তাই আমি আপনাকে immutability-helperরাষ্ট্র আপডেট করার জন্য প্যাকেজ ব্যবহার করার পরামর্শ দিচ্ছি ।

কীভাবে রাষ্ট্র আপডেট করবেন সে সম্পর্কে এই উত্তরটি দেখুন immutability helper


2
@ অহগোদবি, this ... এটি.স্টেট.সোমপ্রোপার্টি since যেহেতু এটি সরাসরি রাজ্যে অ্যাক্সেস করছে না - এটি একটি নতুন অনুশাসনকে ফিরিয়ে দেয় somePropertyএবং আমরা এটি পরিবর্তন করছি
শুভম খাতরী

4
এটি আমার পক্ষে কার্যকর হয়নি .. আমি প্রতিক্রিয়া সংস্করণটি ব্যবহার করছি @ 15.6.1
রাজীব

5
@ স্টোফফেস আমরা গভীর ক্লোন নিশ্চিত করতে লোড্যাশ ব্যবহার করতে পারি, তবে সকলেই এই লাইব্রেরিটিকে কেবল স্টেটের জন্য অন্তর্ভুক্ত করবে না
শুভম খাত্রি

15
এটি কি reactjs.org/docs/… লঙ্ঘন করে না ? যদি নেস্টেড অবজেক্টে দুটি পরিবর্তন ব্যাচ করা হয় তবে সর্বশেষ পরিবর্তনটি প্রথমটিকে ওভাররাইট করে। সুতরাং সবচেয়ে সঠিক this.setState((prevState) => ({nested: {...prevState.nested, propertyToSet: newValue}})
উপায়টি হ'ল

2
আমি মনে করি না যে আপনার ...prevState,শেষ উদাহরণে আপনার প্রয়োজন আছে , আপনি somePropertyএবং কেবল তার শিশুরা
জেমার জোন্স

140

এটি একটি লাইনে লিখতে

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

12
সেটস্টেটের মধ্যে সরাসরি এই স্টেটটি অ্যাক্সেস না করে সেটস্টেটের জন্য আপডেটেটরটি ব্যবহার করার পরামর্শ দেওয়া হয়। reactjs.org/docs/react-component.html#setstate
রঘু তেজা

6
আমি বিশ্বাস করি যে এটি বলছে, this.stateততক্ষণে পড়বেন না setStateএবং এটির নতুন মান হবে বলে আশা করবেন না । this.stateভিতরে কলিং বনাম setState। বা আমার সাথে স্পষ্ট নয় এমন উত্তরোত্তর নিয়েও কোন সমস্যা আছে?
trpt4him

2
যেমন ট্র্টপটহিম বলেছেন, আপনি যে লিঙ্কটি this.stateপরে অ্যাক্সেস করার সমস্যা নিয়ে কথা বলেছেন setState। এছাড়া আমরা ক্ষণস্থায়ী নেই this.stateকরার setStateঅপারেটর বিস্তার বৈশিষ্ট্য। এটি অবজেক্ট.অ্যাসাইন () হিসাবে একই। github.com/tc39/proposal-object-rest-spread
Yoseph

3
@ রঘুতেজা হয়ত কেবল তৈরি করা this.setState(currentState => { someProperty: { ...currentState.someProperty, flag: false} });এই সমস্যাটি এড়াতে পারবেন?
ওয়েবউইম

আমি সম্পূর্ণরূপে ইউজস্টেট হুক দিয়ে কীভাবে এটি অর্জন করতে হবে তার উত্তরটি যুক্ত করেছি ।
অ্যান্ড্রু

89

কখনও কখনও সরাসরি উত্তর সবচেয়ে ভাল হয় না :)

সংক্ষিপ্ত সংস্করণ:

এই কোড

this.state = {
    someProperty: {
        flag: true
    }
}

কিছু সহজ হিসাবে সহজ করা উচিত

this.state = {
    somePropertyFlag: true
}

দীর্ঘ সংস্করণ:

বর্তমানে আপনার প্রতিক্রিয়াতে নেস্টেড রাষ্ট্রের সাথে কাজ করা উচিত নয় । কারণ প্রতিক্রিয়া নেস্টেড রাজ্যগুলির সাথে কাজ করা ভিত্তিক নয় এবং এখানে প্রস্তাবিত সমস্ত সমাধান হ্যাক হিসাবে দেখায়। তারা কাঠামো ব্যবহার করে না তবে এটির সাথে লড়াই করে। তারা কিছু সম্পত্তি গোষ্ঠীবদ্ধ করার সন্দেহজনক উদ্দেশ্যে এত পরিষ্কার কোড না লেখার পরামর্শ দেয়। সুতরাং তারা চ্যালেঞ্জের উত্তর হিসাবে খুব আকর্ষণীয় তবে ব্যবহারিকভাবে অকেজো।

নিম্নলিখিত রাষ্ট্রটি কল্পনা করতে দিন:

{
    parent: {
        child1: 'value 1',
        child2: 'value 2',
        ...
        child100: 'value 100'
    }
}

আপনি যদি কেবল একটি মান পরিবর্তন করেন তবে কী হবে child1? প্রতিক্রিয়া প্রদর্শনটিকে পুনরায় রেন্ডার করবে না কারণ এটি অগভীর তুলনা ব্যবহার করে এবং এটি দেখতে পাবে যে parentসম্পত্তিটি পরিবর্তন হয়নি। রাষ্ট্রীয় বস্তুকে সরাসরি বিটিডব্লিউ রূপান্তর করা সাধারণভাবে একটি খারাপ অভ্যাস হিসাবে বিবেচিত হয়।

সুতরাং আপনাকে পুরো parentঅবজেক্টটি পুনরায় তৈরি করতে হবে । তবে এক্ষেত্রে আমরা আরও একটি সমস্যা পূরণ করব। প্রতিক্রিয়া ভাববে যে সমস্ত শিশু তাদের মান পরিবর্তন করেছে এবং তাদের সমস্তকে পুনরায় রেন্ডার করবে। পারফরম্যান্সের জন্য অবশ্যই এটি ভাল নয়।

কিছু জটিল যুক্তি লিখে এখনও এই সমস্যার সমাধান সম্ভব shouldComponentUpdate()তবে আমি এখানে থেমে সংক্ষিপ্ত সংস্করণ থেকে সহজ সমাধানটি ব্যবহার করতে পছন্দ করব।


4
আমি মনে করি এমন ব্যবহারের কেস রয়েছে যেখানে নেস্টেড স্টেট পুরোপুরি ঠিক আছে। উদাহরণস্বরূপ একটি রাষ্ট্র কী-মূল্যের জোড়গুলি গতিশীলভাবে ট্র্যাক করে। এখানে আপনি কীভাবে শুধুমাত্র একক প্রবেশের জন্য রাজ্যকে আপডেট করতে পারবেন তা এখানে দেখুন: reactjs.org/docs/…
পোড়াস

1
অগভীর তুলনা ডিফল্টরূপে খাঁটি উপাদানগুলির জন্য ব্যবহৃত হয়।
বাসেল শিশানী

4
আমি আপনার সম্মানে একটি বেদী তৈরি করতে চাই এবং প্রতিদিন সকালে এটির জন্য প্রার্থনা করি। এই উত্তরটি পৌঁছাতে আমার তিন দিন সময় লেগেছে যা OBVIOUS নকশা সিদ্ধান্তের পুরোপুরি ব্যাখ্যা করে। নেস্টেড রাষ্ট্র আরও মানব-পঠনযোগ্য বলে মনে হচ্ছে বলে প্রত্যেকে কেবল স্প্রেড অপারেটর ব্যবহার করতে বা অন্যান্য হ্যাকগুলি করার চেষ্টা করে।
এডিফ

1
তারপরে আপনি কীভাবে পরামর্শ দিন, ইন্টারেক্টিভ ট্রি রেন্ডারিংয়ের মতো কাজগুলি করতে প্রতিক্রিয়া ব্যবহার করার জন্য (উদাহরণস্বরূপ, আমার সংস্থার বিশ্বের বিভিন্ন স্থানে, বিভিন্ন স্থানে বিভিন্ন ধরণের, বিভিন্ন জায়গায় বিভিন্ন সংখ্যক সেন্সর রয়েছে) (80+ ), এবং অফ কোর্স এগুলি একটি শ্রেণিবিন্যাসে সংগঠিত হয় কারণ প্রতিটি মোতায়েনের জন্য হাজার হাজার ডলার ব্যয় হয় এবং এটি একটি সম্পূর্ণ প্রকল্প, সুতরাং শ্রেণিবদ্ধতা ব্যতীত এগুলি পরিচালনা করা অসম্ভব)। আপনি কীভাবে গাছের মতো গাছগুলিকে প্রতিক্রিয়াতে মডেল করবেন না তা সম্পর্কে আমি বেশ কৌতূহলী।
ড্যানি আলেজান্দ্রো

10
মনে হচ্ছে অ-তুচ্ছ গভীরতার পুনরাবৃত্তিমূলক কাঠামো হিসাবে সংরক্ষণ করা এমন কোনও কিছু উপস্থাপনের জন্য প্রতিক্রিয়া তৈরি করা হয়নি। গাছের দৃষ্টিভঙ্গি প্রায় প্রতিটি জটিল অ্যাপ্লিকেশনে (জিমেইল, ফাইল ম্যানেজার, যে কোনও ডকুমেন্ট ম্যানেজমেন্ট সিস্টেম, ..) উপস্থিত হওয়ায় এটি কিছুটা হতাশার মতো। আমি এই জিনিসগুলির জন্য প্রতিক্রিয়া ব্যবহার করেছি, তবে সর্বদা একটি প্রতিক্রিয়াশীল জিলিওট ছিল প্রত্যেককে বলছেন যে আপনি অ্যান্টি-প্যাটার্ন করছেন এবং সমাধানের পরামর্শ দিচ্ছেন যে প্রতিটি নোডের অবস্থায় গাছের গভীর কপিগুলি রাখা হচ্ছে (হ্যাঁ, 80 টি অনুলিপি)। আমি একটি নন-হ্যাকি ট্রি-ভিউ উপাদান দেখতে পছন্দ করব যা কোনও প্রতিক্রিয়া বিধি ভঙ্গ করে না।
ড্যানি আলেজান্দ্রো

61

দাবি পরিত্যাগী

প্রতিক্রিয়াযুক্ত নেস্টেড স্টেট ভুল নকশা

এই দুর্দান্ত উত্তর পড়ুন ।

 

এই উত্তরের পিছনে যুক্তি:

প্রতিক্রিয়াটির সেটস্টেটটি কেবল একটি বিল্ট-ইন সুবিধা, তবে আপনি শীঘ্রই বুঝতে পারবেন যে এটির সীমাবদ্ধতা রয়েছে। কাস্টম বৈশিষ্ট্য এবং ফোর্সআপ্টেটের বুদ্ধিমান ব্যবহার ব্যবহার আপনাকে আরও অনেক কিছু দেয়। উদাহরণ:

class MyClass extends React.Component {
    myState = someObject
    inputValue = 42
...

মোবএক্স, উদাহরণস্বরূপ, খাঁজ পুরোপুরি করে এবং কাস্টম পর্যবেক্ষণযোগ্য বৈশিষ্ট্য ব্যবহার করে।
প্রতিক্রিয়া উপাদানগুলিতে রাজ্যের পরিবর্তে পর্যবেক্ষণগুলি ব্যবহার করুন।

 


আপনার দুর্দশার উত্তর - উদাহরণ এখানে দেখুন

নেস্টেড সম্পত্তি যা আছে তা আপডেট করার জন্য আরও একটি ছোট উপায় আছে।

this.setState(state => {
  state.nested.flag = false
  state.another.deep.prop = true
  return state
})

এক লাইনে

 this.setState(state => (state.nested.flag = false, state))

দ্রষ্টব্য: এটি এখানে কমা অপারেটর ~ এমডিএন , এটি এখানে কর্মে এটি দেখুন (স্যান্ডবক্স)

এটি অনুরূপ (যদিও এটি রাষ্ট্রের রেফারেন্স পরিবর্তন করে না)

this.state.nested.flag = false
this.forceUpdate()

এই প্রসঙ্গে সূক্ষ্ম পার্থক্যের জন্য forceUpdateএবং setStateসংযুক্ত উদাহরণটি দেখুন।

অবশ্যই এটি কয়েকটি মূল নীতিগুলি অপব্যবহার করছে, যেমনটি stateকেবল পঠনযোগ্য হওয়া উচিত তবে আপনি যেহেতু পুরানো রাষ্ট্রটি তাত্ক্ষণিকভাবে ত্যাগ করছেন এবং এটি নতুন রাষ্ট্রের সাথে প্রতিস্থাপন করছেন, এটি সম্পূর্ণ ঠিক।

সতর্কতা

যদিও রাষ্ট্রযুক্ত উপাদানগুলি সঠিকভাবে আপডেট হবে এবং পুনরায় রেন্ডার করবে ( এই গোটচা ব্যতীত ) , প্রপসগুলি শিশুদের কাছে প্রচার করতে ব্যর্থ হবে (স্পাইমাস্টারের মন্তব্য নীচে দেখুন) । আপনি কী করছেন তা যদি আপনি জানেন তবেই এই কৌশলটি ব্যবহার করুন।

উদাহরণস্বরূপ, আপনি একটি পরিবর্তিত ফ্ল্যাট প্রপ পাস করতে পারেন যা আপডেট এবং সহজেই পাস হয়।

render(
  //some complex render with your nested state
  <ChildComponent complexNestedProp={this.state.nested} pleaseRerender={Math.random()}/>
)

কমপ্লেক্সনেস্টড্রপের জন্য রেফারেন্স পরিবর্তিত না হওয়া সত্ত্বেও ( shouldComp घटकUpdate )

this.props.complexNestedProp === nextProps.complexNestedProp

যখনই পিতা বা মাতা উপাদান আপডেট হয় তখন উপাদানটি পুনরায় রেন্ডার হবে , যা কল করার পরে this.setStateবা this.forceUpdateপিতামাতার ক্ষেত্রে।

রাষ্ট্রকে পরিবর্তিত করার প্রভাব

নেস্টেড স্টেট ব্যবহার করা এবং রাজ্যকে সরাসরি রূপান্তর করা বিপজ্জনক কারণ বিভিন্ন বিষয়গুলি (ইচ্ছাকৃতভাবে বা না) রাষ্ট্রের বিভিন্ন (পুরানো) রেফারেন্স ধারণ করতে পারে এবং কখন আপডেট করতে হবে তা অবশ্যই জানে না (উদাহরণস্বরূপ যখন ব্যবহার করার সময় PureComponentবা shouldComponentUpdateফিরে আসার জন্য প্রয়োগ করা হয় false) বা হয় নীচের উদাহরণে মত পুরানো ডেটা প্রদর্শন করার উদ্দেশ্যে।

এমন একটি টাইমলাইন কল্পনা করুন যা historicতিহাসিক ডেটা রেন্ডার করার কথা রয়েছে, হাতের নীচে ডেটা পরিবর্তনের ফলে অপ্রত্যাশিত আচরণ হবে কারণ এটি পূর্ববর্তী আইটেমগুলিকেও পরিবর্তন করবে।

রাষ্ট্রীয় প্রবাহ রাষ্ট্রীয় প্রবাহ-নেস্টেড

যাইহোক এখানে আপনি দেখতে পাচ্ছেন যে Nested PureChildClassপ্রচারগুলিতে ব্যর্থ হয়ে প্রপসের কারণে এটি রেন্ডার হয়নি।


12
আপনার কোনও প্রতিক্রিয়া অবস্থা কোথাও পরিবর্তন করা উচিত নয়। যদি নেস্টেড উপাদান থাকে যা state.nested বা state.another থেকে ডেটা ব্যবহার করে তবে তারা পুনরায় রেন্ডার করবে না বা তাদের সন্তানদেরও দেবে না। এটি কারণ বস্তুটি পরিবর্তন হয়নি, সুতরাং প্রতিক্রিয়া মনে করে যে কিছুই পরিবর্তন হয়নি।
জেরেগাম্বা

@ স্পাইমাস্টার 356 আমি এটিকে সমাধান করতে আমার উত্তর আপডেট করেছি। এছাড়াও লক্ষ করুন যে মোবএক্স, উদাহরণস্বরূপ, stateপুরোপুরি খাঁজ এবং কাস্টম পর্যবেক্ষণযোগ্য বৈশিষ্ট্য ব্যবহার করে। প্রতিক্রিয়া setStateকেবল একটি অন্তর্নিহিত সুবিধার, তবে আপনি শীঘ্রই বুঝতে পারবেন যে এটির সীমাবদ্ধতা রয়েছে। কাস্টম বৈশিষ্ট্য এবং বুদ্ধিমানের ব্যবহার forceUpdateআপনাকে আরও অনেক কিছু দেয়। প্রতিক্রিয়া উপাদানগুলিতে রাজ্যের পরিবর্তে পর্যবেক্ষণগুলি ব্যবহার করুন।
কিওয়ার্টি

এছাড়াও আমি রিঅ্যাক্ট-এক্সপেরিমেন্টস.েরোকুয়াপস / স্টেট- ফ্লো (উপরে টুকরো টুকরো লিঙ্ক) একটি উদাহরণ যুক্ত করেছি
কিওয়ার্টি

আপনি যদি উদাহরণস্বরূপ কোনও ডাটাবেস থেকে নেস্টেড বৈশিষ্ট্যযুক্ত কোনও বস্তুটিকে রাজ্যে লোড করেন? সেক্ষেত্রে কীভাবে নেস্টেড রাষ্ট্র এড়ানো যায়?
tobiv

3
@ টোবিভ আনার সময় ডেটাটি অন্য কাঠামোতে রূপান্তর করা আরও ভাল তবে এটি ইউজকেসের উপর নির্ভর করে। কোনও রাজ্যে নেস্টেড অবজেক্ট বা অ্যারেজ অবজেক্ট থাকা ঠিক আছে যদি আপনি এগুলি কিছু উপাত্তের কমপ্যাক্ট ইউনিট হিসাবে মনে করেন । সমস্যা দেখা দেয় যখন আপনার ইউআই স্যুইচগুলি বা অন্যান্য পর্যবেক্ষণযোগ্য ডেটা সংরক্ষণ করা দরকার (যেমন ডেটা যা অবিলম্বে দৃষ্টিভঙ্গিটি পরিবর্তন করা উচিত) সেগুলি অবশ্যই ফ্ল্যাট হতে হবে যাতে সঠিকভাবে অভ্যন্তরীণ প্রতিক্রিয়াশীল ভিন্ন ভিন্ন অ্যালগরিদমগুলি ট্রিগার করতে পারে। অন্যান্য নেস্টেড অবজেক্টে পরিবর্তনের জন্য, this.forceUpdate()নির্দিষ্টটিকে ট্রিগার করা বা প্রয়োগ করা সহজ shouldComponentUpdate
কিওয়ার্টি

21

আপনি যদি ES2015 ব্যবহার করছেন তবে আপনার Object.assign এ অ্যাক্সেস রয়েছে। নেস্টেড অবজেক্টটি আপডেট করার জন্য আপনি নীচে এটি ব্যবহার করতে পারেন।

this.setState({
  someProperty: Object.assign({}, this.state.someProperty, {flag: false})
});

আপনি বিদ্যমান বৈশিষ্ট্যগুলির সাথে আপডেট হওয়া বৈশিষ্ট্যগুলি মার্জ করুন এবং রাষ্ট্র আপডেট করার জন্য প্রত্যাবর্তিত অবজেক্টটি ব্যবহার করুন।

সম্পাদনা করুন: কারকড নির্দেশিত হিসাবে রাজ্যটি সরাসরি রূপান্তরিত হয়নি তা নিশ্চিত করার জন্য অ্যাসাইন ফাংশনটিতে লক্ষ্য হিসাবে একটি খালি বস্তু যুক্ত করা হয়েছে।


12
এবং আমি ভুল হতে পারি তবে আমি মনে করি না আপনি ES2015 ছাড়াই প্রতিক্রিয়া ব্যবহার করছেন ।
ম্যাডব্রেকস

16
const newState = Object.assign({}, this.state);
newState.property.nestedProperty = "new value";
this.setState(newState);

1
এখানে আরও মার্জিত সমাধান বলে মনে হচ্ছে, 1) সেটস্টেটের ভিতরে ক্লান্তিকর বিস্তারটি এড়ানো এবং 2) সেটস্টেটের অভ্যন্তরে নতুনভাবে সুন্দরভাবে স্থাপন করা, সরাসরি সেটস্টেটের অভ্যন্তরে পরিবর্তিত হওয়া এড়ানো। সর্বশেষ তবে কমপক্ষে 3 নয়) কোনও সাধারণ কাজের জন্য কোনও লাইব্রেরির ব্যবহার এড়ানো
ওয়েবউইম্যান

দুটি উদাহরণ সমতুল্য নয়। যদি propertyএতে কয়েকটি নেস্টেড বৈশিষ্ট্য থাকে তবে প্রথমটি তাদের মুছবে, দ্বিতীয়টি তা করবে না। codesandbox.io/s/nameless-pine-42thu
Qwerty

কিওয়ার্টি, আপনি ঠিক বলেছেন, চেষ্টা করার জন্য ধন্যবাদ। আমি ES6 সংস্করণ সরিয়েছি।
eyecandy.dev

স্ট্রাইফওয়ার্ড এবং সরল!
টনি সেপিয়া

আমি আপনার সমাধান ব্যবহার। আমার রাজ্য আপত্তি ছোট, এবং এটি দুর্দান্ত কাজ করেছে। প্রতিক্রিয়া কি কেবল পরিবর্তিত রাষ্ট্রের জন্য রেন্ডার দেবে বা এটি সবকিছু রেন্ডার করবে?
কেনজি নোগুচি

14

এই সাহায্যে অনেক গ্রন্থাগার আছে। উদাহরণস্বরূপ, অপরিবর্তনীয়তা-সহায়ক ব্যবহার করে :

import update from 'immutability-helper';

const newState = update(this.state, {
  someProperty: {flag: {$set: false}},
};
this.setState(newState);

লড্যাশ / এফপি সেট ব্যবহার করুন :

import {set} from 'lodash/fp';

const newState = set(["someProperty", "flag"], false, this.state);

লড্যাশ / এফপি মার্জ ব্যবহার করা :

import {merge} from 'lodash/fp';

const newState = merge(this.state, {
  someProperty: {flag: false},
});

আপনি যদি ব্যবহার করেন তবে lodashআপনি সম্ভবত চেষ্টা করে দেখতে চান _.cloneDeepএবং ক্লোন অনুলিপি হিসাবে স্থিতি সেট করতে চান ।
Yixing লিউ

@ আইসিংলিউ: আমি ব্যবহারের উত্তরটি আপডেট করেছি lodash/fp, তাই আমাদের মিউটেশন নিয়ে চিন্তা করতে হবে না।
টোকল্যান্ড

সিনট্যাক্সের পাশাপাশি লোড্যাশ / এফপি বাছাই mergeবা setফাংশন করার কোনও সুবিধা ?
তোইভো সোওয়ান

উত্তম উত্তর, সম্ভবত আপনি যুক্ত করতে চান যে আপনাকে কল করতে হবে this.setState(newState) লড্যাশ / এফপি পদ্ধতিগুলির জন্যও । আরেকটি গ্যাচা হ'ল লোডাশের .set(নন- এফপি ) যুক্তিগুলির একটি আলাদা ক্রম রয়েছে যা আমাকে কিছু সময়ের জন্য ছড়িয়ে দিয়েছে।
তোয়ভো সোওয়ান

7

আমরা এই ধরণের সমস্যাগুলি পরিচালনা করতে ইমার https://github.com/mweststrate/immer ব্যবহার করি ।

এই কোডটি কেবল আমাদের উপাদানগুলির একটিতে প্রতিস্থাপন করে

this.setState(prevState => ({
   ...prevState,
        preferences: {
            ...prevState.preferences,
            [key]: newValue
        }
}));

এর সাথে

import produce from 'immer';

this.setState(produce(draft => {
    draft.preferences[key] = newValue;
}));

নিমজ্জন দিয়ে আপনি আপনার রাজ্যটিকে "সাধারণ বিষয়" হিসাবে পরিচালনা করেন। প্রক্সি বস্তুগুলির সাথে জাদুটি ঘটনার পিছনে ঘটে।


6

এই থ্রেডে দেওয়া প্রথম উত্তরে এখানে একটি ভিন্নতা যার জন্য কোনও অতিরিক্ত প্যাকেজ, গ্রন্থাগার বা বিশেষ ফাংশন প্রয়োজন হয় না।

state = {
  someProperty: {
    flag: 'string'
  }
}

handleChange = (value) => {
  const newState = {...this.state.someProperty, flag: value}
  this.setState({ someProperty: newState })
}

নির্দিষ্ট নেস্টেড ক্ষেত্রের স্থিতি নির্ধারণ করতে, আপনি পুরো বস্তুটি সেট করে রেখেছেন। আমি একটি ভেরিয়েবল তৈরি করে এবং ES2015 স্প্রেড অপারেটরটি ব্যবহার করে এটির newStateমধ্যে বর্তমান অবস্থার বিষয়বস্তুগুলি প্রথমে ছড়িয়ে দিয়েছিলাম । তারপরে, আমি this.state.flagনতুন মানটির সাথে মানটির প্রতিস্থাপন করেছি (যেহেতু আমি বর্তমান অবস্থাকে বস্তুতে ছড়িয়ে দেওয়ার flag: value পরে সেট করেছি, বর্তমান অবস্থায় flagক্ষেত্রটি ওভাররাইড করা হবে)। তারপরে, আমি কেবল somePropertyআমার newStateবস্তুর স্থিতি স্থির করি।


6

যদিও বাসা বাঁধাই আপনার উপাদানগুলির সাথে কীভাবে আচরণ করা উচিত তা ঠিক নয়, কখনও কখনও একক স্তরের বাসা বাঁধার জন্য সহজ কিছু জন্য।

এই মত একটি রাষ্ট্রের জন্য

state = {
 contact: {
  phone: '888-888-8888',
  email: 'test@test.com'
 }
 address: {
  street:''
 },
 occupation: {
 }
}

একটি পুনরায় ব্যবহারযোগ্য পদ্ধতি ive এর মত দেখতে হবে।

handleChange = (obj) => e => {
  let x = this.state[obj];
  x[e.target.name] = e.target.value;
  this.setState({ [obj]: x });
};

তারপরে আপনি ঠিক করতে চান এমন প্রতিটি নীড়ের জন্য কেবল আপত্তিটির নাম দিয়ে যাচ্ছেন ...

<TextField
 name="street"
 onChange={handleChange('address')}
 />

4

আমি এই সমাধানটি ব্যবহার করেছি।

যদি আপনার মতো নেস্টেড রাজ্য থাকে:

   this.state = {
          formInputs:{
            friendName:{
              value:'',
              isValid:false,
              errorMsg:''
            },
            friendEmail:{
              value:'',
              isValid:false,
              errorMsg:''
            }
}

আপনি হ্যান্ডেল চেঞ্জ ফাংশনটি ঘোষণা করতে পারেন যা বর্তমান স্থিতিটি অনুলিপি করে এবং পরিবর্তিত মান সহ এটি পুনরায় নিয়োগ করে-

handleChange(el) {
    let inputName = el.target.name;
    let inputValue = el.target.value;

    let statusCopy = Object.assign({}, this.state);
    statusCopy.formInputs[inputName].value = inputValue;

    this.setState(statusCopy);
  }

ইভেন্ট শ্রোতার সাথে এখানে এইচটিএমএল

<input type="text" onChange={this.handleChange} " name="friendName" />

নিশ্চিত করেছে। যদি আপনি ইতিমধ্যে নেস্টেড বৈশিষ্ট্যগুলির সাথে ইতিমধ্যে একটি প্রতিষ্ঠিত প্রকল্পটি নিয়ে কাজ করছেন তবে এটি দুর্দান্ত কাজ করে।
ধাতু_জ্যাক 1

4

রাজ্যের একটি অনুলিপি তৈরি করুন:

let someProperty = JSON.parse(JSON.stringify(this.state.someProperty))

এই অবজেক্টে পরিবর্তন করুন:

someProperty.flag = "false"

এখন রাষ্ট্র আপডেট করুন

this.setState({someProperty})

সেটস্টেট হ'ল অবিচ্ছিন্ন। সুতরাং এটি আপডেট হওয়ার সময়, অন্য কেউ এই ফাংশনটিতে কল করতে পারেন এবং রাজ্যের পুরানো সংস্করণটি অনুলিপি করতে পারেন।
আভিভ বেন শাবাত

3

যদিও আপনি শ্রেণিভিত্তিক প্রতিক্রিয়া উপাদানটির একটি রাজ্য সম্পর্কে জিজ্ঞাসা করেছিলেন, ইউস্টস্ট হুকের ক্ষেত্রেও একই সমস্যা বিদ্যমান। আরও খারাপ: ইউজস্টেট হুক আংশিক আপডেট গ্রহণ করে না। সুতরাং যখন ইউজার স্টেট হুক চালু হয়েছিল তখন এই প্রশ্নটি খুব প্রাসঙ্গিক হয়ে ওঠে।

প্রশ্নটিতে আরও আধুনিক পরিস্থিতি রয়েছে যেখানে ব্যবহারের স্টেট হুক ব্যবহৃত হয় তা নিশ্চিত করার জন্য আমি নীচের উত্তরটি পোস্ট করার সিদ্ধান্ত নিয়েছি:

যদি আপনি পেয়েছেন:

const [state, setState] = useState({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

আপনি বর্তমানের ক্লোনিং করে এবং ডেটার প্রয়োজনীয় বিভাগগুলিকে প্যাচ করে নেস্টেড সম্পত্তি সেট করতে পারেন:

setState(current => { ...current, someProperty: { ...current.someProperty, flag: false } });

অথবা আপনি অবজেক্টের ক্লোনিং এবং প্যাচিং সহজ করতে ইমার লাইব্রেরি ব্যবহার করতে পারেন।

অথবা আপনি জটিল (স্থানীয় এবং বৈশ্বিক) রাষ্ট্রীয় ডেটা পুরোপুরি পরিচালনা করতে এবং কর্মক্ষমতা উন্নত করতে হুকস্টেট লাইব্রেরি (অস্বীকৃতি: আমি একজন লেখক) ব্যবহার করতে পারেন (পড়ুন: অপ্টিমাইজেশানটি রেন্ডারিং সম্পর্কে চিন্তা করবেন না):

import { useStateLink } from '@hookstate/core' 
const state = useStateLink({ someProperty: { flag: true, otherNestedProp: 1 }, otherProp: 2 })

ক্ষেত্রটি রেন্ডার করতে:

state.nested.someProperty.nested.flag.get()
// or 
state.get().someProperty.flag

নেস্টেড ফিল্ড সেট করুন:

state.nested.someProperty.nested.flag.set(false)

এখানে হুকস্টেটের উদাহরণ রয়েছে, যেখানে গাছ গাছের মতো ডেটা কাঠামোয় রাজ্য গভীরভাবে / পুনরাবৃত্তভাবে বাসা বেঁধে থাকে ।


2

এখনও দুটি উল্লেখ করা হয়নি:

  1. যদি আপনি গভীরভাবে বাসা বেঁধে থাকেন তবে বিবেচনা করুন যে আপনি যদি শিশুদের বস্তুর মূলে বসতে পুনর্গঠন করতে পারেন। এটি ডেটা আপডেট করা সহজ করে তোলে।
  2. রেডাক্স ডক্সে তালিকাভুক্ত অপরিবর্তনীয় অবস্থার পরিচালনার জন্য অনেকগুলি সহজ গ্রন্থাগার রয়েছে । আমি ইমারকে সুপারিশ করছি যেহেতু এটি আপনাকে একটি মিউটরিটিভ পদ্ধতিতে কোড লিখতে দেয় তবে পর্দার পিছনে প্রয়োজনীয় ক্লোনিং পরিচালনা করে। এটি ফলস্বরূপ বস্তুকেও হিমশীতল করে তোলে যাতে আপনি দুর্ঘটনাক্রমে পরে এটিকে পরিবর্তন করতে পারবেন না।

2

জিনিসগুলি জেনেরিক করার জন্য, আমি @ শুভখাত্রীর এবং @ কিওয়ারটির উত্তরগুলিতে কাজ করেছি।

রাষ্ট্র অবজেক্ট

this.state = {
  name: '',
  grandParent: {
    parent1: {
      child: ''
    },
    parent2: {
      child: ''
    }
  }
};

ইনপুট নিয়ন্ত্রণ

<input
  value={this.state.name}
  onChange={this.updateState}
  type="text"
  name="name"
/>
<input
  value={this.state.grandParent.parent1.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent1.child"
/>
<input
  value={this.state.grandParent.parent2.child}
  onChange={this.updateState}
  type="text"
  name="grandParent.parent2.child"
/>

আপডেট স্টেট পদ্ধতি

@ শুভখাত্রীর উত্তর হিসাবে সেটস্টেট

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const oldstate = this.state;
  const newstate = { ...oldstate };
  let newStateLevel = newstate;
  let oldStateLevel = oldstate;

  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      newStateLevel[path[i]] = event.target.value;
    } else {
      newStateLevel[path[i]] = { ...oldStateLevel[path[i]] };
      oldStateLevel = oldStateLevel[path[i]];
      newStateLevel = newStateLevel[path[i]];
    }
  }
  this.setState(newstate);
}

@ কিওয়ারটির উত্তর হিসাবে সেটস্টেট করুন

updateState(event) {
  const path = event.target.name.split('.');
  const depth = path.length;
  const state = { ...this.state };
  let ref = state;
  for (let i = 0; i < depth; i += 1) {
    if (i === depth - 1) {
      ref[path[i]] = event.target.value;
    } else {
      ref = ref[path[i]];
    }
  }
  this.setState(state);
}

দ্রষ্টব্য: এই উপরের পদ্ধতিগুলি অ্যারেগুলিতে কাজ করবে না


2

আপনার উপাদান রাষ্ট্রের সম্পূর্ণ অনুলিপি তৈরি করার আশেপাশে ইতিমধ্যে উত্থাপিত উদ্বেগগুলি আমি খুব গুরুত্ব সহকারে নিচ্ছি । এই বলে, আমি দৃ strongly়ভাবে ইমারকে পরামর্শ দেব ।

import produce from 'immer';

<Input
  value={this.state.form.username}
  onChange={e => produce(this.state, s => { s.form.username = e.target.value }) } />

এটি React.PureComponent(যেমন রিঅ্যাক্ট দ্বারা অগভীর রাষ্ট্রের তুলনা) এর জন্য কাজ করা উচিত কারণ Immerএকটি নির্বিচারে গভীর রাষ্ট্র গাছকে দক্ষতার সাথে অনুলিপি করার জন্য চতুরতার সাথে একটি প্রক্সি অবজেক্ট ব্যবহার করে। ইমিট্যাবিলিটি হেল্পারের মতো লাইব্রেরির তুলনায় ইমার আরও প্রকারভেদযুক্ত এবং জাভাস্ক্রিপ্ট এবং টাইপসক্রিপ্ট ব্যবহারকারীদের জন্য একই রকম।


টাইপস্ক্রিপ্ট ইউটিলিটি ফাংশন

function setStateDeep<S>(comp: React.Component<any, S, any>, fn: (s: 
Draft<Readonly<S>>) => any) {
  comp.setState(produce(comp.state, s => { fn(s); }))
}

onChange={e => setStateDeep(this, s => s.form.username = e.target.value)}

1
stateUpdate = () => {
    let obj = this.state;
    if(this.props.v12_data.values.email) {
      obj.obj_v12.Customer.EmailAddress = this.props.v12_data.values.email
    }
    this.setState(obj)
}

1
আমি এটিকে সঠিক বলে মনে করি না, যেহেতু objকেবলমাত্র রাজ্যের একটি রেফারেন্স, সুতরাং এটির মাধ্যমে আপনি আসল this.stateবস্তুটির পরিবর্তন করছেন
সিপ্রিয়ান টোমাইগা

0

আমার ক্ষেত্রে এটির জন্য আমার একটি প্রকল্পের ফর্ম ছিল আমি উদাহরণস্বরূপ আপনার আইডি, এবং একটি নাম রেখেছি এবং আমি নেস্টেড প্রকল্পের জন্য রাষ্ট্র বজায় রাখতে পারি।

return (
  <div>
      <h2>Project Details</h2>
      <form>
        <Input label="ID" group type="number" value={this.state.project.id} onChange={(event) => this.setState({ project: {...this.state.project, id: event.target.value}})} />
        <Input label="Name" group type="text" value={this.state.project.name} onChange={(event) => this.setState({ project: {...this.state.project, name: event.target.value}})} />
      </form> 
  </div>
)

আমাকে জানতে দাও!


0

এরকম কিছু যথেষ্ট হতে পারে,

const isObject = (thing) => {
    if(thing && 
        typeof thing === 'object' &&
        typeof thing !== null
        && !(Array.isArray(thing))
    ){
        return true;
    }
    return false;
}

/*
  Call with an array containing the path to the property you want to access
  And the current component/redux state.

  For example if we want to update `hello` within the following obj
  const obj = {
     somePrimitive:false,
     someNestedObj:{
        hello:1
     }
  }

  we would do :
  //clone the object
  const cloned = clone(['someNestedObj','hello'],obj)
  //Set the new value
  cloned.someNestedObj.hello = 5;

*/
const clone = (arr, state) => {
    let clonedObj = {...state}
    const originalObj = clonedObj;
    arr.forEach(property => {
        if(!(property in clonedObj)){
            throw new Error('State missing property')
        }

        if(isObject(clonedObj[property])){
            clonedObj[property] = {...originalObj[property]};
            clonedObj = clonedObj[property];
        }
    })
    return originalObj;
}

const nestedObj = {
    someProperty:true,
    someNestedObj:{
        someOtherProperty:true
    }
}

const clonedObj = clone(['someProperty'], nestedObj);
console.log(clonedObj === nestedObj) //returns false
console.log(clonedObj.someProperty === nestedObj.someProperty) //returns true
console.log(clonedObj.someNestedObj === nestedObj.someNestedObj) //returns true

console.log()
const clonedObj2 = clone(['someProperty','someNestedObj','someOtherProperty'], nestedObj);
console.log(clonedObj2 === nestedObj) // returns false
console.log(clonedObj2.someNestedObj === nestedObj.someNestedObj) //returns false
//returns true (doesn't attempt to clone because its primitive type)
console.log(clonedObj2.someNestedObj.someOtherProperty === nestedObj.someNestedObj.someOtherProperty) 

0

আমি জানি এটি একটি পুরানো প্রশ্ন তবে আমি কীভাবে এটি অর্জন করেছি তা ভাগ করে নিতে চেয়েছিলাম। কনস্ট্রাক্টরের অবস্থা ধরে নেওয়া এইরকম দেখাচ্ছে:

  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      user: {
        email: ""
      },
      organization: {
        name: ""
      }
    };

    this.handleChange = this.handleChange.bind(this);
  }

আমার handleChangeফাংশনটি এরকম:

  handleChange(e) {
    const names = e.target.name.split(".");
    const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
    this.setState((state) => {
      state[names[0]][names[1]] = value;
      return {[names[0]]: state[names[0]]};
    });
  }

এবং নিশ্চিত করুন যে আপনি সেই অনুযায়ী ইনপুটগুলির নাম রাখবেন:

<input
   type="text"
   name="user.email"
   onChange={this.handleChange}
   value={this.state.user.firstName}
   placeholder="Email Address"
/>

<input
   type="text"
   name="organization.name"
   onChange={this.handleChange}
   value={this.state.organization.name}
   placeholder="Organization Name"
/>

0

আমি হ্রাস অনুসন্ধানের সাথে নেস্টেড আপডেটগুলি করি :

উদাহরণ:

রাজ্যে নেস্টেড ভেরিয়েবলগুলি:

state = {
    coords: {
        x: 0,
        y: 0,
        z: 0
    }
}

কাজ:

handleChange = nestedAttr => event => {
  const { target: { value } } = event;
  const attrs = nestedAttr.split('.');

  let stateVar = this.state[attrs[0]];
  if(attrs.length>1)
    attrs.reduce((a,b,index,arr)=>{
      if(index==arr.length-1)
        a[b] = value;
      else if(a[b]!=null)
        return a[b]
      else
        return a;
    },stateVar);
  else
    stateVar = value;

  this.setState({[attrs[0]]: stateVar})
}

ব্যবহার করুন:

<input
value={this.state.coords.x}
onChange={this.handleTextChange('coords.x')}
/>

0

এটি আমার প্রাথমিক স্টেট ate

    const initialStateInput = {
        cabeceraFamilia: {
            familia: '',
            direccion: '',
            telefonos: '',
            email: ''
        },
        motivoConsulta: '',
        fechaHora: '',
        corresponsables: [],
    }

হুক বা আপনি এটি রাজ্যের সাথে প্রতিস্থাপন করতে পারেন (শ্রেণি উপাদান)

const [infoAgendamiento, setInfoAgendamiento] = useState(initialStateInput);

হ্যান্ডেলচঞ্জের জন্য পদ্ধতি

const actualizarState = e => {
    const nameObjects = e.target.name.split('.');
    const newState = setStateNested(infoAgendamiento, nameObjects, e.target.value);
    setInfoAgendamiento({...newState});
};

নেস্টেড রাজ্যগুলির সাথে সেট স্টেটের পদ্ধতি

const setStateNested = (state, nameObjects, value) => {
    let i = 0;
    let operativeState = state;
    if(nameObjects.length > 1){
        for (i = 0; i < nameObjects.length - 1; i++) {
            operativeState = operativeState[nameObjects[i]];
        }
    }
    operativeState[nameObjects[i]] = value;
    return state;
}

অবশেষে এটি আমি ব্যবহার করি তা ইনপুট

<input type="text" className="form-control" name="cabeceraFamilia.direccion" placeholder="Dirección" defaultValue={infoAgendamiento.cabeceraFamilia.direccion} onChange={actualizarState} />

0

আপনি যদি আপনার প্রকল্পে ফর্মিক ব্যবহার করছেন তবে এই জিনিসগুলি হ্যান্ডেল করার কিছু সহজ উপায় আছে। ফর্মিকটি করার সবচেয়ে সহজ উপায় এখানে।

প্রথমে আপনার প্রাথমিক মানগুলি ফর্মিক সূচনা বৈশিষ্ট্যের ভিতরে বা প্রতিক্রিয়াতে সেট করুন। অবস্থা

এখানে, প্রাথমিক মানগুলি প্রতিক্রিয়া অবস্থায় সংজ্ঞায়িত করা হয়

   state = { 
     data: {
        fy: {
            active: "N"
        }
     }
   }

ফর্মিক initiValuesবৈশিষ্ট্যের ভিতরে ফর্মিক ক্ষেত্রের জন্য প্রাথমিকের মানগুলি উপরে সংজ্ঞা দিন

<Formik
 initialValues={this.state.data}
 onSubmit={(values, actions)=> {...your actions goes here}}
>
{({ isSubmitting }) => (
  <Form>
    <Field type="checkbox" name="fy.active" onChange={(e) => {
      const value = e.target.checked;
      if(value) setFieldValue('fy.active', 'Y')
      else setFieldValue('fy.active', 'N')
    }}/>
  </Form>
)}
</Formik>

রাজ্যটি সেট করতে ফর্মিক ফাংশনের stringপরিবর্তে রাষ্ট্রটি আপডেট booleanহওয়া চেকটিতে একটি কনসোল তৈরি করুন setFieldValueবা ফর্মিক রাষ্ট্রীয় মানগুলির মধ্যে পরিবর্তনগুলি দেখতে রিঅ্যাক্ট ডিবাগার সরঞ্জামের সাথে যান।


0

এই কোড চেষ্টা করুন:

this.setState({ someProperty: {flag: false} });

তবে somePropertyএটি উপরের কোডটি কার্যকর করার পরে অবজেক্টে উপস্থিত অন্য যে কোনও বৈশিষ্ট্যকে সরিয়ে ফেলবে এবং কেবলমাত্র flagসম্পত্তি থাকবে
ইয়াসাস

0

আমি একটি বইতে নিম্নলিখিত দেখেছি:

this.setState(state => state.someProperty.falg = false);

তবে আমি নিশ্চিত না যে এটি ঠিক কিনা ..

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.