रिएक्ट हुक ऑब्जेक्ट के साथ उपयोग () करते हैं


114

अद्यतन स्थिति का सही तरीका क्या है, एक नेस्टेड ऑब्जेक्ट है, रिएक्ट विद हुक्स?

export Example = () => {
  const [exampleState, setExampleState] = useState(
  {masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b"
           fieldTwoTwo: "c"
           }
        }
   })

किसी क्षेत्र setExampleStateको अपडेट exampleStateकरने के लिए कोई कैसे उपयोग करेगा a?

const a = {
masterField: {
        fieldOne: "a",
        fieldTwo: {
           fieldTwoOne: "b",
           fieldTwoTwo: "c"
           }
        },
  masterField2: {
        fieldOne: "c",
        fieldTwo: {
           fieldTwoOne: "d",
           fieldTwoTwo: "e"
           }
        },
   }
}

b (मूल्यों में परिवर्तन)?

const b = {masterField: {
        fieldOne: "e",
        fieldTwo: {
           fieldTwoOne: "f"
           fieldTwoTwo: "g"
           }
        }
   })


आप मौजूदा वस्तु में नए ऑब्जेक्ट कुंजी मूल्य जोड़ने का मतलब है?
बस कोड

@Justcode पहले उदाहरण के लिए हां, दूसरे उदाहरण के लिए सिर्फ मौजूदा वस्तु को बदलकर
isaacsultan

onValueChange = {() => setSelection ({... prev, id_1: true})}
उमर बख्श

जवाबों:


122

आप इस तरह से नए मान पास कर सकते हैं

  setExampleState({...exampleState,  masterField2: {
        fieldOne: "c",
        fieldTwo: {
           fieldTwoOne: "d",
           fieldTwoTwo: "e"
           }
        },
   }})

2
महान, कि उत्तर भाग ए! क्या आप भाग बी के लिए सबसे अच्छा अभ्यास जानते हैं?
isassultan

1
{// नए मूल्यों} के masterFieldबजाय केवल पिछले ही बदल रहा हैmasterField2 setExampleState({...exampleState, masterField:
aseferov

3
प्रसार ऑपरेटर का उपयोग करते समय उथले नकल के बारे में पता होना। उदाहरण के लिए देखें: stackoverflow.com/questions/43638938/…
जोओ मार्कोस ग्रिस

9
यदि आप अपने डिस्पैचर के साथ एक ही राज्य का उपयोग कर रहे हैं, तो आपको एक फ़ंक्शन का उपयोग करना चाहिए। setExampleState( exampleState => ({...exampleState, masterField2: {...etc} }) );
माइकल हार्ले

62

यदि कोई व्यक्ति ऑब्जेक्ट के लिए यूज़स्टैट () हुक अपडेट को खोज रहा है

- Through Input

        const [state, setState] = useState({ fName: "", lName: "" });
        const handleChange = e => {
            const { name, value } = e.target;
            setState(prevState => ({
                ...prevState,
                [name]: value
            }));
        };

        <input
            value={state.fName}
            type="text"
            onChange={handleChange}
            name="fName"
        />
        <input
            value={state.lName}
            type="text"
            onChange={handleChange}
            name="lName"
        />
   ***************************

 - Through onSubmit or button click
    
        setState(prevState => ({
            ...prevState,
            fName: 'your updated value here'
         }));

3
ठीक वही जो मेरे द्वारा खोजा जा रहा था। बहुत बढ़िया!
स्टैक्डएक्टर

42

आम तौर पर आपको रिएक्ट अवस्था में गहरी नेस्टेड वस्तुओं के लिए देखना चाहिए। अप्रत्याशित व्यवहार से बचने के लिए, राज्य को पूरी तरह से अपडेट किया जाना चाहिए। जब आपके पास गहरी वस्तुएं होती हैं, तो आप उन्हें अपरिवर्तनीयता के लिए गहरी क्लोनिंग करते हैं, जो कि रिएक्ट में काफी महंगा हो सकता है। क्यों?

एक बार जब आप राज्य को क्लोन कर लेते हैं, तो रिएक्ट पुनर्गणना और सब कुछ फिर से प्रस्तुत करेगा जो चर पर निर्भर करता है, भले ही वे बदल नहीं गए हों!

इसलिए, अपने मुद्दे को हल करने का प्रयास करने से पहले, सोचें कि आप पहले राज्य को कैसे समतल कर सकते हैं। जैसे ही आप ऐसा करते हैं, आपको सुंदर उपकरण मिलेंगे जो बड़े राज्यों के साथ काम करने में मदद करेंगे, जैसे कि उपयोगरेडर ()।

मामले में आप इसके बारे में सोचा, लेकिन अभी भी आश्वस्त कर रहे हैं आप एक गहरा नीडिंत राज्य वृक्ष का उपयोग करने की जरूरत है, तो आप अभी भी तरह पुस्तकालयों के साथ useState () का उपयोग कर सकते immutable.js और अचल स्थिति-हेल्पर । उत्परिवर्तन के बारे में चिंता किए बिना वे गहरी वस्तुओं को अपडेट या क्लोन करना सरल बनाते हैं।


आप हुकस्टेट (अस्वीकरण: मैं एक लेखक हूं) का उपयोग जटिल (स्थानीय और वैश्विक) स्टेट डेटा को गहन क्लोनिंग के बिना और फिर अनावश्यक अपडेट के बारे में चिंता किए बिना प्रबंधित करने के लिए कर सकता हूं - हुकस्टेट आपके लिए इसे संभाल लेंगे।
एंड्रयू

8

धन्यवाद फिलिप ने मेरी मदद की - मेरा उपयोग मामला था, मेरे पास बहुत सारे इनपुट फ़ील्ड के साथ एक फॉर्म था इसलिए मैंने ऑब्जेक्ट के रूप में प्रारंभिक स्थिति बनाए रखी और मैं ऑब्जेक्ट स्टेट को अपडेट करने में सक्षम नहीं था। उपरोक्त पोस्ट ने मेरी मदद की :)

const [projectGroupDetails, setProjectGroupDetails] = useState({
    "projectGroupId": "",
    "projectGroup": "DDD",
    "project-id": "",
    "appd-ui": "",
    "appd-node": ""    
});

const inputGroupChangeHandler = (event) => {
    setProjectGroupDetails((prevState) => ({
       ...prevState,
       [event.target.id]: event.target.value
    }));
}

<Input 
    id="projectGroupId" 
    labelText="Project Group Id" 
    value={projectGroupDetails.projectGroupId} 
    onChange={inputGroupChangeHandler} 
/>



6

मुझे पार्टी में देर हो गई .. :)

@aseferov उत्तर बहुत अच्छी तरह से काम करता है जब इरादा पूरे ऑब्जेक्ट संरचना को फिर से दर्ज करना है। हालाँकि, यदि लक्ष्य / लक्ष्य किसी ऑब्जेक्ट में विशिष्ट फ़ील्ड मान को अद्यतन करना है, तो मेरा मानना ​​है कि नीचे का दृष्टिकोण बेहतर है।

परिस्थिति:

const [infoData, setInfoData] = useState({
    major: {
      name: "John Doe",
      age: "24",
      sex: "M",
    },

    minor:{
      id: 4,
      collegeRegion: "south",

    }

  });

एक विशिष्ट रिकॉर्ड को अपडेट करने के लिए पिछले राज्य को याद करने की आवश्यकता होगी prevState

यहाँ:

setInfoData((prevState) => ({
      ...prevState,
      major: {
        ...prevState.major,
        name: "Tan Long",
      }
    }));

शायद

setInfoData((prevState) => ({
      ...prevState,
      major: {
        ...prevState.major,
        name: "Tan Long",
      },
      minor: {
        ...prevState.minor,
        collegeRegion: "northEast"

    }));

मुझे आशा है कि यह किसी को भी इसी तरह की समस्या को हल करने में मदद करता है।


1
मेरा एक सवाल है। हमें कोष्ठक में फ़ंक्शन को लपेटने की आवश्यकता क्यों है? मुझे यकीन नहीं है कि हुड के नीचे क्या चल रहा है। क्या आपको पता होगा या मैं उस पर और अधिक कहां पढ़ सकता हूं?
क्ननन

2
@MichaelRamage हम फ़ंक्शन को कोष्ठक में क्यों लपेटते हैं:: ()इसे सरलता से उत्तर देने के लिए; ऐसा इसलिए setInfoData है क्योंकि यह प्रकृति द्वारा एक उच्च क्रम है। यह एक तर्क के रूप में दूसरे कार्य पर ले जा सकता है, हुक द्वारा प्रदान की गई शक्ति के सौजन्य से: useState। मुझे आशा है कि इस अनुच्छेद उच्च क्रम कार्यों पर अधिक स्पष्टता प्रदान करेगा: sitepoint.com/higher-order-functions-javascript
Olamigoke फिलिप

2
बहुत उपयोगी है, विशेष रूप से उस मामले के लिए जहां आप एक संपत्ति को अद्यतन करने की कोशिश कर रहे हैं, जिसमें कई परतें गहरी हैं, जैसे: first.second.third - अन्य उदाहरण पहले कवर करते हैं। पहले, लेकिन पहले नहीं। second.third
क्रेग

3
function App() {

  const [todos, setTodos] = useState([
    { id: 1, title: "Selectus aut autem", completed: false },
    { id: 2, title: "Luis ut nam facilis et officia qui", completed: false },
    { id: 3, title: "Fugiat veniam minus", completed: false },
    { id: 4, title: "Aet porro tempora", completed: true },
    { id: 5, title: "Laboriosam mollitia et enim quasi", completed: false }
  ]);

  const changeInput = (e) => {todos.map(items => items.id === parseInt(e.target.value) && (items.completed = e.target.checked));
 setTodos([...todos], todos);}
  return (
    <div className="container">
      {todos.map(items => {
        return (
          <div key={items.id}>
            <label>
<input type="checkbox" 
onChange={changeInput} 
value={items.id} 
checked={items.completed} />&nbsp; {items.title}</label>
          </div>
        )
      })}
    </div>
  );
}

1

मुझे लगता है कि सबसे अच्छा समाधान Immer है । यह आपको ऑब्जेक्ट को अपडेट करने की अनुमति देता है जैसे आप सीधे फ़ील्ड्स को संशोधित कर रहे हैं (masterField.fieldOne.fieldx = 'abc')। लेकिन यह निश्चित रूप से वास्तविक वस्तु को नहीं बदलेगा। यह एक ड्राफ्ट ऑब्जेक्ट पर सभी अपडेट एकत्र करता है और आपको अंत में एक अंतिम ऑब्जेक्ट देता है जिसका उपयोग आप मूल ऑब्जेक्ट को बदलने के लिए कर सकते हैं।


0

मैं आपको एक उपयोगिता फ़ंक्शन को अयोग्य रूप से अद्यतन करने वाली वस्तुओं को छोड़ देता हूं

/**
 * Inmutable update object
 * @param  {Object} oldObject     Object to update
 * @param  {Object} updatedValues Object with new values
 * @return {Object}               New Object with updated values
 */
export const updateObject = (oldObject, updatedValues) => {
  return {
    ...oldObject,
    ...updatedValues
  };
};

तो आप इसे इस तरह से उपयोग कर सकते हैं

const MyComponent = props => {

  const [orderForm, setOrderForm] = useState({
    specialities: {
      elementType: "select",
      elementConfig: {
        options: [],
        label: "Specialities"
      },
      touched: false
    }
  });


// I want to update the options list, to fill a select element

  // ---------- Update with fetched elements ---------- //

  const updateSpecialitiesData = data => {
    // Inmutably update elementConfig object. i.e label field is not modified
    const updatedOptions = updateObject(
      orderForm[formElementKey]["elementConfig"],
      {
        options: data
      }
    );
    // Inmutably update the relevant element.
    const updatedFormElement = updateObject(orderForm[formElementKey], {
      touched: true,
      elementConfig: updatedOptions
    });
    // Inmutably update the relevant element in the state.
    const orderFormUpdated = updateObject(orderForm, {
      [formElementKey]: updatedFormElement
    });
    setOrderForm(orderFormUpdated);
  };

  useEffect(() => {
      // some code to fetch data
      updateSpecialitiesData.current("specialities",fetchedData);
  }, [updateSpecialitiesData]);

// More component code
}

यदि आपके पास यहां अधिक उपयोगिताओं नहीं हैं: https://es.reactjs.org/docs/update.html


0

प्रारंभ में मैंने उपयोग में ऑब्जेक्ट का उपयोग किया था, लेकिन फिर मैं जटिल मामलों के लिए उपयोग किया थारेडर हुक। जब मैंने कोड को रीक्रिएट किया तो मुझे प्रदर्शन में सुधार महसूस हुआ।

जब आप जटिल राज्य तर्क जिसमें कई उप-मान शामिल होते हैं या जब अगला राज्य पिछले एक पर निर्भर करता है, तब उपयोग करने के लिए उपयोग किया जाता है।

उपयोगरेडर रिएक्ट डॉक्स

मैंने पहले से ही अपने उपयोग के लिए इस तरह के हुक को लागू किया है:

/**
 * Same as useObjectState but uses useReducer instead of useState
 *  (better performance for complex cases)
 * @param {*} PropsWithDefaultValues object with all needed props 
 * and their initial value
 * @returns [state, setProp] state - the state object, setProp - dispatch 
 * changes one (given prop name & prop value) or multiple props (given an 
 * object { prop: value, ...}) in object state
 */
export function useObjectReducer(PropsWithDefaultValues) {
  const [state, dispatch] = useReducer(reducer, PropsWithDefaultValues);

  //newFieldsVal={[field_name]: [field_value], ...}
  function reducer(state, newFieldsVal) {
    return { ...state, ...newFieldsVal };
  }

  return [
    state,
    (newFieldsVal, newVal) => {
      if (typeof newVal !== "undefined") {
        const tmp = {};
        tmp[newFieldsVal] = newVal;
        dispatch(tmp);
      } else {
        dispatch(newFieldsVal);
      }
    },
  ];
}

अधिक संबंधित हुक


0

, इसे इस उदाहरण की तरह करें:

वस्तुओं की पहली जीव अवस्था:

const [isSelected, setSelection] = useState({ id_1: false }, { id_2: false }, { id_3: false });

फिर उन पर मूल्य बदलें:

// if the id_1 is false make it true or return it false.

onValueChange={() => isSelected.id_1 == false ? setSelection({ ...isSelected, id_1: true }) : setSelection({ ...isSelected, id_1: false })}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.