রিডেক্সে নির্দিষ্ট অ্যারে আইটেমের মধ্যে কীভাবে একক মান আপডেট করা যায়


105

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

এটি আমার রাজ্যের উদাহরণ

{
 name: "some name",
 subtitle: "some subtitle",
 contents: [
   {title: "some title", text: "some text"},
   {title: "some other title", text: "some other text"}
 ]
}

এবং আমি বর্তমানে এটি আপডেট করছি

case 'SOME_ACTION':
   return { ...state, contents: action.payload }

যেখানে action.payloadনতুন মানগুলি সহ পুরো অ্যারে রয়েছে। তবে এখন আমার কেবল বিষয়বস্তু অ্যারেতে দ্বিতীয় আইটেমের পাঠ্য আপডেট করতে হবে এবং এর মতো কিছু কাজ করে না

case 'SOME_ACTION':
   return { ...state, contents[1].text: action.payload }

যেখানে action.payloadএখন একটি টেক্সট আমি আপডেটের জন্য প্রয়োজন হয়।

উত্তর:


57

আপনি প্রতিক্রিয়া অপরিবর্তনীয় সাহায্যকারীদের ব্যবহার করতে পারেন

import update from 'react-addons-update';

// ...    

case 'SOME_ACTION':
  return update(state, { 
    contents: { 
      1: {
        text: {$set: action.payload}
      }
    }
  });

যদিও আমি ভাবব আপনি সম্ভবত আরও কিছু এইরকম করছিলেন?

case 'SOME_ACTION':
  return update(state, { 
    contents: { 
      [action.id]: {
        text: {$set: action.payload}
      }
    }
  });

আসলে, আমার হ্রাসকারীর ভিতরে কোনওভাবে প্রতিক্রিয়া থেকে এই সহায়কদের অন্তর্ভুক্ত করা দরকার?
ইলজা

8
যদিও প্যাকেজটি সরানো হয়েছে kolodny/immutability-helper, তাই এখন এটি yarn add immutability-helperএবংimport update from 'immutability-helper';
স্যাকওয়েব ডেভেলপার ২৩:৫7-এ

আমার কেসটি হুবহু একই, তবে আমি যখন অ্যারেতে উপাদানগুলির মধ্যে একটিতে অবজেক্টটি আপডেট করি তখন আপডেট হওয়া মানটি উপাদানউইলরিসিপপ্রসেসগুলিতে প্রতিফলিত হয় না। আমি সরাসরি আমার মানচিত্রের স্টেটটোপ্রপসে বিষয়বস্তু ব্যবহার করি, এটি প্রতিফলিত করার জন্য আমাদের কী মানচিত্রের স্টেটটোপ্রোপে অন্য কিছু ব্যবহার করতে হবে?
শ্রুতি গুপ্ত

171

আপনি ব্যবহার করতে পারেন map। এখানে একটি বাস্তবায়ন উদাহরণ:

case 'SOME_ACTION':
   return { 
       ...state, 
       contents: state.contents.map(
           (content, i) => i === 1 ? {...content, text: action.payload}
                                   : content
       )
    }

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

@ ভেন্তুরা হ্যাঁ, এটি ভাল কারণ এটি অ্যারের জন্য একটি নতুন রেফারেন্স তৈরি করছে এবং আপডেট করার উদ্দেশ্যে একের জন্য একটি সরল নতুন অবজেক্ট তৈরি করেছে (এবং কেবলমাত্র এটিই) যা আপনি চান
আইভান্ডেডেলা

3
আমি মনে করি এটি সেরা অভিনব
যীশু গোমেজ

12
আমি এটি প্রায়শই করি তবে প্রয়োজনীয় সূচকটি আপডেট করার পরিবর্তে সমস্ত উপাদানগুলির পুনরাবৃত্তি করা তুলনামূলকভাবে ব্যয়বহুল বলে মনে হয়।
বেন ক্র্যাসি

সুন্দর এক ! আমি এটা ভালোবাসি !
নেট বেন

21

আপনাকে এক লাইনে সবকিছু করতে হবে না:

case 'SOME_ACTION':
  const newState = { ...state };
  newState.contents = 
    [
      newState.contents[0],
      {title: newState.contnets[1].title, text: action.payload}
    ];
  return newState

1
আপনি ঠিক বলেছেন, আমি দ্রুত সমাধান করেছি did বিটিডব্লিউ, অ্যারে স্থির দৈর্ঘ্য কি? এবং আপনি যে সূচকটি সংশোধন করতে চান তা কি ঠিক হয়ে গেছে? বর্তমান পদ্ধতিটি কেবলমাত্র ছোট অ্যারে এবং স্থির সূচক সহ কার্যকর।
Yuya

2
আপনার কেস বডিটি {} এ মোড়ুন, যেহেতু কনস্টেটি ব্লক স্কপড।
বেনি পাওয়ারস

12

পার্টিতে খুব দেরি হলেও এখানে একটি জেনেরিক সমাধান যা প্রতিটি সূচক মানের সাথে কাজ করে।

  1. আপনি পুরানো অ্যারে থেকে নতুন indexপরিবর্তন করতে এবং পরিবর্তন করতে চান এমনটি ছড়িয়ে দিয়েছেন ।

  2. আপনি চান ডেটা যোগ করুন।

  3. indexআপনি অ্যারের শেষের দিকে পরিবর্তন করতে চেয়েছিলেন তা থেকে নতুন অ্যারে তৈরি করুন এবং ছড়িয়ে দিন

let index=1;// probabbly action.payload.id
case 'SOME_ACTION':
   return { 
       ...state, 
       contents: [
          ...state.contents.slice(0,index),
          {title: "some other title", text: "some other text"},
         ...state.contents.slice(index+1)
         ]
    }

হালনাগাদ:

কোডটি সহজ করার জন্য আমি একটি ছোট মডিউল তৈরি করেছি, সুতরাং আপনাকে কেবল একটি ফাংশন কল করতে হবে:

case 'SOME_ACTION':
   return {
       ...state,
       contents: insertIntoArray(state.contents,index, {title: "some title", text: "some text"})
    }

আরও উদাহরণের জন্য, সংগ্রহস্থলটি একবার দেখুন

ফাংশন স্বাক্ষর:

insertIntoArray(originalArray,insertionIndex,newData)

3

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

আসুন ভান করুন এটি আপনার রাষ্ট্র:

const state = {
    houses: {
        gryffindor: {
          points: 15
        },
        ravenclaw: {
          points: 18
        },
        hufflepuff: {
          points: 7
        },
        slytherin: {
          points: 5
        }
    }
}

এবং আপনি রাভেনক্লোতে 3 পয়েন্ট যুক্ত করতে চান

const key = "ravenclaw";
  return {
    ...state, // copy state
    houses: {
      ...state.houses, // copy houses
      [key]: {  // update one specific house (using Computed Property syntax)
        ...state.houses[key],  // copy that specific house's properties
        points: state.houses[key].points + 3   // update its `points` property
      }
    }
  }

স্প্রেড অপারেটর ব্যবহার করে আপনি সমস্ত কিছু অক্ষত রেখে কেবলমাত্র নতুন রাষ্ট্র আপডেট করতে পারেন।

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


3

আমার ক্ষেত্রে আমি লুইসের উত্তরের ভিত্তিতে এরকম কিছু করেছি:

...State object...
userInfo = {
name: '...',
...
}

...Reducer's code...
case CHANGED_INFO:
return {
  ...state,
  userInfo: {
    ...state.userInfo,
    // I'm sending the arguments like this: changeInfo({ id: e.target.id, value: e.target.value }) and use them as below in reducer!
    [action.data.id]: action.data.value,
  },
};

0

আমি আমার প্রকল্পের জন্য এটি এটি করেছি:

const markdownSaveActionCreator = (newMarkdownLocation, newMarkdownToSave) => ({
  type: MARKDOWN_SAVE,
  saveLocation: newMarkdownLocation,
  savedMarkdownInLocation: newMarkdownToSave  
});

const markdownSaveReducer = (state = MARKDOWN_SAVED_ARRAY_DEFAULT, action) => {
  let objTemp = {
    saveLocation: action.saveLocation, 
    savedMarkdownInLocation: action.savedMarkdownInLocation
  };

  switch(action.type) {
    case MARKDOWN_SAVE:
      return( 
        state.map(i => {
          if (i.saveLocation === objTemp.saveLocation) {
            return Object.assign({}, i, objTemp);
          }
          return i;
        })
      );
    default:
      return state;
  }
};

0

আমি আশঙ্কা করছি যে map()অ্যারের পদ্ধতি ব্যবহার করা ব্যয়বহুল হতে পারে যেহেতু পুরো অ্যারেটি পুনরাবৃত্তি করা উচিত। পরিবর্তে, আমি একটি নতুন অ্যারে সংযুক্ত করি যা তিনটি অংশ নিয়ে গঠিত:

  • মাথা - পরিবর্তিত আইটেমের আগে আইটেম
  • পরিবর্তিত আইটেম
  • লেজ - পরিবর্তিত আইটেম পরে আইটেম

এখানে উদাহরণ হিসাবে আমি আমার কোডটি ব্যবহার করেছি (এনজিআরএক্স, তবুও অন্যান্য রেডাক্স বাস্তবায়নের জন্য ম্যাচানিজমটি একই রকম):

// toggle done property: true to false, or false to true

function (state, action) {
    const todos = state.todos;
    const todoIdx = todos.findIndex(t => t.id === action.id);

    const todoObj = todos[todoIdx];
    const newTodoObj = { ...todoObj, done: !todoObj.done };

    const head = todos.slice(0, todoIdx - 1);
    const tail = todos.slice(todoIdx + 1);
    const newTodos = [...head, newTodoObj, ...tail];
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.