ইউজস্টেট হুক সেটরটি ভুলভাবে স্থিতি ওভাররাইট করে


31

এখানে সমস্যাটি রয়েছে: আমি একটি বোতাম ক্লিকে 2 টি ফাংশন কল করার চেষ্টা করছি। উভয় ফাংশন রাষ্ট্র আপডেট করে (আমি ইউজস্টেট হুক ব্যবহার করছি)। প্রথম ফাংশনটি সঠিকভাবে 'নতুন 1' এ মান 1 আপডেট করে, তবে 1 এস (সেটটাইমআউট) পরে দ্বিতীয় ফাংশনটি অগ্নিকাণ্ডে আসে এবং এটি 2 এর মানকে 'নতুন 2' বাট-এ পরিবর্তিত করে! এটির মান 1 সেট '1' এ ফিরে আসে। ইহা কি জন্য ঘটিতেছে? আগাম ধন্যবাদ!

import React, { useState } from "react";

const Test = () => {
  const [state, setState] = useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState({ ...state, value1: "new 1" });
  };
  const changeValue2 = () => {
    setState({ ...state, value2: "new 2" });
  };

  return (
    <>
      <button
        onClick={() => {
          changeValue1();
          setTimeout(changeValue2, 1000);
        }}
      >
        CHANGE BOTH
      </button>
      <h1>{state.value1}</h1>
      <h1>{state.value2}</h1>
    </>
  );
};

export default Test;

আপনি কি শুরুতে রাষ্ট্র লগ করতে পারেন changeValue2?
ড্যানস্টার্নস

1
আমি আপনাকে সুপারিশ করছি যে আপনি দুটি বস্তুকে দুটি পৃথক কলে বিভক্ত করুন useStateবা তার পরিবর্তে ব্যবহার করুন useReducer
জ্যারেড স্মিথ

হ্যাঁ - এটি দ্বিতীয়। স্টেট ()
পেডারসেন

const [state, ...], এবং তারপরে সেটারে এটি উল্লেখ করা হচ্ছে ... এটি সর্বদা একই অবস্থা ব্যবহার করবে।
জোহানেস কুহন

কর্মের সর্বোত্তম কোর্স: 2 টি পৃথক useStateকল ব্যবহার করুন , প্রতিটি "ভেরিয়েবল" এর জন্য একটি।
ডিমা তিস্নেক

উত্তর:


30

বন্ধ নরক স্বাগতম । এই সমস্যাটি ঘটে কারণ যখনই setStateডাকা হয়, stateএকটি নতুন মেমরি রেফারেন্স আসে তবে ফাংশনগুলি changeValue1এবং changeValue2বন্ধ হওয়ার কারণে, পুরানো প্রাথমিক stateরেফারেন্স রাখে।

একটি সমাধান নিশ্চিত করার setStateথেকে changeValue1এবং changeValue2সর্বশেষ রাষ্ট্র একটি ব্যবহার করা পায় কলব্যাক (ক প্যারামিটার হিসাবে পূর্বের অবস্থায় থাকার):

import React, { useState } from "react";

const Test = () => {
  const [state, setState] = useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
  };
  const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
  };

  // ...
};

আপনি এখানে এবং এখানে এই বন্ধকরণ ইস্যু সম্পর্কে একটি বিস্তৃত আলোচনা খুঁজে পেতে পারেন ।


ইউজস্টেট হুক সহ একটি কলব্যাক একটি অনিবন্ধিত বৈশিষ্ট্য বলে মনে হচ্ছে , আপনি কি নিশ্চিত যে এটি কাজ করে?
এইচএমআর

@ এইচএমআর হ্যাঁ, এটি কাজ করে এবং এটি অন্য পৃষ্ঠায় নথিভুক্ত। এখানে "কার্যকরী আপডেটগুলি" বিভাগটি দেখুন: reactjs.org/docs/hooks-references.html ("নতুন রাজ্যটি যদি পূর্ববর্তী রাজ্যটি ব্যবহার করে গণনা করা হয়, আপনি সেটস্টেটে কোনও ফাংশন পাস করতে পারেন")
আলবার্তো ত্রিন্ডে

1
@ অ্যালবার্তো ট্রিন্ডেটাভেরেস হ্যাঁ, আমি পাশাপাশি ডক্সগুলিও দেখছিলাম, কিছুই খুঁজে পেলাম না। ধন্যবাদ উত্তরের জন্য অনেক!
বারটেক

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

1
আপনাকে ধন্যবাদ # আলবার্তো ট্রিন্ডেড্যাভারেস! দুর্দান্ত এক
জোসে সালগাদো

19

আপনার ফাংশনগুলি এর মতো হওয়া উচিত:

const changeValue1 = () => {
    setState((prevState) => ({ ...prevState, value1: "new 1" }));
};
const changeValue2 = () => {
    setState((prevState) => ({ ...prevState, value2: "new 2" }));
};

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


6

যখন changeValue2আহ্বান করা হয়, প্রাথমিক অবস্থা অনুষ্ঠিত হয় তাই রাজ্যটি মূল অবস্থায় ফিরে আসে এবং তারপরে value2সম্পত্তি লেখা হয়।

এর পরের বারের অনুরোধ changeValue2করা হবে, এটি রাষ্ট্রকে ধরে রাখে {value1: "1", value2: "new 2"}, তাই value1সম্পত্তিটি ওভাররাইট করা হয়।

setStateপ্যারামিটারের জন্য আপনার একটি তীর ফাংশন প্রয়োজন ।

const Test = () => {
  const [state, setState] = React.useState({
    value1: "1",
    value2: "2"
  });

  const changeValue1 = () => {
    setState(prev => ({ ...prev, value1: "new 1" }));
  };
  const changeValue2 = () => {
    setState(prev => ({ ...prev, value2: "new 2" }));
  };

  return (
    <React.Fragment>
      <button
        onClick={() => {
          changeValue1();
          setTimeout(changeValue2, 1000);
        }}
      >
        CHANGE BOTH
      </button>
      <h1>{state.value1}</h1>
      <h1>{state.value2}</h1>
    </React.Fragment>
  );
};

ReactDOM.render(<Test />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>


3

যা ঘটছে তা হ'ল উভয়ই changeValue1এবং তারা যে-রেন্ডারটি তৈরি করেছিল সেগুলি থেকেchangeValue2 রাষ্ট্রটি দেখতে পায় , তাই যখন আপনার উপাদানগুলি প্রথমবারের জন্য রেন্ডার হয় তখন এই 2 টি কার্যটি দেখুন:

state= {
  value1: "1",
  value2: "2"
}

আপনি যখন বোতামটি ক্লিক করেন, changeValue1প্রথমে তাকে ডাকা হয় {value1: "new1", value2: "2"}এবং প্রত্যাশা অনুযায়ী রাষ্ট্র পরিবর্তন করে ।

এখন, 1 সেকেন্ডের পরে, changeValue2বলা হয়, তবে এই ফাংশনটি এখনও প্রাথমিক অবস্থা ( {value1; "1", value2: "2"}) দেখতে পায় , সুতরাং যখন এই ফাংশনটি এইভাবে রাষ্ট্রটিকে আপডেট করে:

setState({ ...state, value2: "new 2" });

আপনাকে দেখে শেষ পর্যন্ত: {value1; "1", value2: "new2"}

সূত্র

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