मैं कैसे रिएक्ट में हुक के साथ फिर से प्रस्तुत करने के लिए घटक को मजबूर कर सकता हूं?


116

हुक के उदाहरण पर विचार करते हुए

   import { useState } from 'react';

   function Example() {
       const [count, setCount] = useState(0);

       return (
           <div>
               <p>You clicked {count} times</p>
               <button onClick={() => setCount(count + 1)}>
                  Click me
               </button>
          </div>
        );
     }

मूल रूप से हम इसका उपयोग करते हैं ।forceUpdate () विधि को फिर से प्रस्तुत करने के लिए घटक को फिर से प्रस्तुत करने के लिए बाध्य करने के लिए बाध्य करें

    class Test extends Component{
        constructor(props){
             super(props);
             this.state = {
                 count:0,
                 count2: 100
             }
             this.setCount = this.setCount.bind(this);//how can I do this with hooks in functional component 
        }
        setCount(){
              let count = this.state.count;
                   count = count+1;
              let count2 = this.state.count2;
                   count2 = count2+1;
              this.setState({count});
              this.forceUpdate();
              //before below setState the component will re-render immediately when this.forceUpdate() is called
              this.setState({count2: count
        }

        render(){
              return (<div>
                   <span>Count: {this.state.count}></span>. 
                   <button onClick={this.setCount}></button>
                 </div>
        }
 }

लेकिन मेरी क्वेरी यह है कि मैं हुक के साथ तुरंत रेंडर करने के लिए कार्यात्मक घटक के ऊपर कैसे बल दे सकता हूं?


1
क्या आप अपने मूल घटक का एक संस्करण पोस्ट कर सकते हैं जो इसका उपयोग करता है this.forceUpdate()? हो सकता है कि इसके बिना एक ही बात को पूरा करने का एक तरीका हो।
जैकब

सेटकाउंट में अंतिम पंक्ति को काट दिया जाता है। यह स्पष्ट नहीं है कि इसकी वर्तमान स्थिति में सेटकाउंट का उद्देश्य क्या है।
एस्टुस फ्लास्क

इसके बाद बस एक कार्रवाई है। मैंने कहा कि सिर्फ इस बारे में समझाने के लिए। TheFUdate () मेरे सवाल में
हेमाद्री दासारी

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

जवाबों:


77

आंतरिक रूप से उपयोग के बाद से useStateया useReducer, यह संभव है :useStateuseReducer

const [, updateState] = React.useState();
const forceUpdate = React.useCallback(() => updateState({}), []);

forceUpdateकेवल परीक्षण या अन्य बकाया मामलों में सामान्य परिस्थितियों में उपयोग करने का इरादा नहीं है। इस स्थिति को अधिक परंपरागत तरीके से संबोधित किया जा सकता है।

setCountअनुचित तरीके से उपयोग किए जाने का एक उदाहरण है forceUpdate, setStateप्रदर्शन के कारणों के लिए अतुल्यकालिक है और इसे केवल इसलिए सिंक्रोनस करने के लिए मजबूर नहीं किया जाना चाहिए क्योंकि राज्य अपडेट सही तरीके से किए गए थे। यदि कोई राज्य पहले से सेट किए गए राज्य पर निर्भर करता है, तो यह अपडाउन फ़ंक्शन के साथ किया जाना चाहिए ,

यदि आपको पिछली स्थिति के आधार पर राज्य को सेट करने की आवश्यकता है, तो नीचे updater तर्क के बारे में पढ़ें।

<...>

अपडेटर फ़ंक्शन द्वारा प्राप्त किए गए दोनों राज्य और प्रॉप्स को अद्यतित होने की गारंटी है। अद्यतनकर्ता का उत्पादन उथले रूप से राज्य में विलय कर दिया गया है।

setCount एक उदाहरण नहीं हो सकता है क्योंकि इसका उद्देश्य स्पष्ट नहीं है, लेकिन updater फ़ंक्शन के लिए यह मामला है:

setCount(){
  this.setState(({count}) => ({ count: count + 1 }));
  this.setState(({count2}) => ({ count2: count + 1 }));
  this.setState(({count}) => ({ count2: count + 1 }));
}

यह 1: 1 से हुक तक अनुवादित होता है, इस अपवाद के साथ कि कॉलबैक के रूप में उपयोग किए जाने वाले फ़ंक्शन को बेहतर रूप से याद किया जाना चाहिए:

   const [state, setState] = useState({ count: 0, count2: 100 });

   const setCount = useCallback(() => {
     setState(({count}) => ({ count: count + 1 }));
     setState(({count2}) => ({ count2: count + 1 }));
     setState(({count}) => ({ count2: count + 1 }));
   }, []);

कैसे const forceUpdate = useCallback(() => updateState({}), []);काम करता है ? क्या यह एक अद्यतन को भी मजबूर करता है?
दाविद मोलनार

2
@ DávidMolnár useCallbackसंस्मरण करता है forceUpdate, इसलिए यह घटक जीवनकाल के दौरान स्थिर रहता है और इसे सुरक्षित रूप से एक प्रस्ताव के रूप में पारित किया जा सकता है। updateState({})प्रत्येक forceUpdateकॉल पर नई वस्तु के साथ राज्य को अपडेट करता है , इसके परिणामस्वरूप फिर से प्रस्तुत किया जाता है। तो हां, यह अपडेट होने पर मजबूर करता है।
एस्टुस फ्लास्क

3
तो, useCallbackभाग वास्तव में आवश्यक नहीं है। इसके बिना ही ठीक काम करना चाहिए।
दाविद मोलनार

और यह काम नहीं करेगा updateState(0)क्योंकि 0यह एक आदिम डेटा प्रकार है? यह एक वस्तु होना चाहिए या updateState([])(एक सरणी के साथ उपयोग) भी काम करेगा?
एंडरू

1
@ और हां, एक राज्य को एक बार अपडेट किया जाता है क्योंकि 0 === 0। हां, एक सरणी काम करेगी क्योंकि यह एक वस्तु भी है। कुछ भी जो समानता जांच पास नहीं करता है, का उपयोग किया जा सकता है, जैसे updateState(Math.random()), या एक काउंटर।
एस्टुस फ्लास्क

29

जैसा कि दूसरों ने उल्लेख किया है, useStateकाम करता है - यहां बताया गया है कि कैसे mobx-react-lite इम्प्लीमेंट अपडेट करता है - आप कुछ ऐसा ही कर सकते हैं।

एक नया हुक परिभाषित करें, useForceUpdate-

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    setTick(tick => tick + 1);
  }, [])
  return update;
}

और इसे एक घटक में उपयोग करें -

const forceUpdate = useForceUpdate();
if (...) {
  forceUpdate(); // force re-render
}

देखें https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts और https://github.com/mobxjs/mobx-react-lite/blob/master/src/useObserver .ts


2
हुक से जो मैं समझता हूं, यह काम नहीं कर सकता है क्योंकि useForceUpdateफ़ंक्शन फिर से रेंडर करने वाले हर बार एक नया फ़ंक्शन लौटाएगा। के लिए forceUpdateकाम करने के लिए जब एक में प्रयोग किया जाता useEffectहै, यह वापस आ जाएगी useCallback(update)देखें kentcdodds.com/blog/usememo-and-usecallback
मार्टिन Ratinaud

धन्यवाद, @MartinRatinaud - हाँ, यह बिना उपयोग के मेमोरी लीक का कारण हो सकता है।
ब्रायन बर्न्स

27

आम तौर पर, आप किसी भी राज्य हैंडलिंग दृष्टिकोण का उपयोग कर सकते हैं जिसे आप एक अद्यतन ट्रिगर करना चाहते हैं।

टाइपस्क्रिप्ट के साथ

कोडैंडबॉक्स उदाहरण

useState

const forceUpdate: () => void = React.useState()[1].bind(null, {})  // see NOTE below

useReducer

const forceUpdate = React.useReducer(() => ({}), {})[1] as () => void

कस्टम हुक के रूप में

इस तरह से आप जो भी दृष्टिकोण पसंद करते हैं उसे बस लपेटें

function useForceUpdate(): () => void {
  return React.useReducer(() => ({}), {})[1] as () => void // <- paste here
}

यह कैसे काम करता है?

" अपडेट को ट्रिगर करने के लिए " रिएक्ट इंजन को बताने का मतलब है कि कुछ मूल्य बदल गया है और यह आपके घटक को फिर से प्रस्तुत करना चाहिए।

[, setState]से useState()एक पैरामीटर की आवश्यकता है। हम एक ताजा वस्तु को बांधकर इससे छुटकारा पा लेते हैं {}
() => ({})में useReducerएक डमी कम करने है कि रिटर्न एक ताजा वस्तु हर बार एक कार्रवाई भेजा जाता है।
{} (ताजा वस्तु) की आवश्यकता होती है ताकि यह राज्य में एक संदर्भ बदलकर एक अद्यतन को चालू कर सके।

पुनश्च: useStateबस useReducerआंतरिक रूप से लपेटता है । स्रोत

नोट: उपयोग के साथ .bind का उपयोग करते हुए रेंडरर्स के बीच फ़ंक्शन संदर्भ में परिवर्तन होता है। यह उपयोग करने के लिए संभव है इसे अंदर लपेटें जैसा कि पहले ही यहां बताया गया है , लेकिन फिर यह एक सेक्सी वन-लाइनर ™ नहीं होगा । Reducer संस्करण पहले से ही रेंडरर्स के बीच संदर्भ समानता रखता है । यह महत्वपूर्ण है यदि आप प्रॉप्स में फ़ोर्सअप फ़ंक्शन को पास करना चाहते हैं।

सादा जेएस

const forceUpdate = React.useState()[1].bind(null, {})  // see NOTE above
const forceUpdate = React.useReducer(() => ({}))[1]

17

@ मिन्हा के जवाब के लिए वैकल्पिक:

यह बहुत साफ हो सकता है useReducer:

const [, forceUpdate] = useReducer(x => x + 1, 0);

उपयोग: forceUpdate()- क्लीनर बिना परम के


13

आप बस उस तरह useState को परिभाषित कर सकते हैं:

const [, forceUpdate] = React.useState(0);

और उपयोग: forceUpdate(n => !n)

उममीद है कि इससे मदद मिलेगी !


7
यदि बल प्रदान किया जाता है तो विफल हो जाएगा, जबकि रेंडर प्रति बार की संख्या भी कहा जाता है।
इजाकी

बस मूल्य बढ़ाते रहो।
गैरी

2
यह त्रुटि-प्रवण है और इसे हटाया या संपादित किया जाना चाहिए।
slikts

11

प्रतिक्रिया के लिए हुक सामान्य प्रश्न हल करें forceUpdate:

const [_, forceUpdate] = useReducer((x) => x + 1, 0);
// usage
<button onClick={forceUpdate}>Force update</button>

काम करने का उदाहरण


10

आपको अधिमानतः केवल आपका घटक राज्य और प्रॉप्स पर निर्भर होना चाहिए और यह अपेक्षा के अनुरूप काम करेगा, लेकिन यदि आपको घटक को फिर से प्रस्तुत करने के लिए मजबूर करने के लिए फ़ंक्शन की आवश्यकता है, तो आप useStateहुक का उपयोग कर सकते हैं और आवश्यकता होने पर फ़ंक्शन को कॉल कर सकते हैं।

उदाहरण

const { useState, useEffect } = React;

function Foo() {
  const [, forceUpdate] = useState();

  useEffect(() => {
    setTimeout(forceUpdate, 2000);
  }, []);

  return <div>{Date.now()}</div>;
}

ReactDOM.render(<Foo />, document.getElementById("root"));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>


ठीक है, लेकिन क्यों React ने इसे पेश किया है। पहले स्थान पर जब घटक पहले के संस्करणों में सेटस्टेट के साथ पुन: प्रस्तुत करता है?
हेमाद्रि दसारी

1
@ थिंक-ट्वाइस मैंने व्यक्तिगत रूप से कभी इसका उपयोग नहीं किया है, और मैं अभी इसके लिए एक अच्छे उपयोग के मामले के बारे में नहीं सोच सकता हूं, लेकिन मुझे लगता है कि यह वास्तव में विशेष उपयोग के मामलों के लिए एक एस्केप हैच है। "आम तौर पर आप सभी का उपयोग करता है से बचने के लिए प्रयास करना चाहिए forceUpdate()और केवल से पढ़ा this.propsऔर this.stateमें render()।"
थोल

1
माना। मैंने कभी भी अपने अनुभव में इसका इस्तेमाल नहीं किया था, लेकिन मुझे पता है कि यह कैसे काम करता है, बस यह समझने की कोशिश कर रहा है कि हुक में एक ही चीज कैसे हो सकती है
हेमाद्रि दसारी

1
@ and I can't think of a good use case for it right now मेरे पास एक है, अगर रिएक्ट द्वारा राज्य को नियंत्रित नहीं किया जाता है, तो कैसे। मैं Redux का उपयोग नहीं करता, लेकिन मैं यह मान रहा हूं कि इसे किसी प्रकार का जोर-जबरदस्ती करना चाहिए। मैं व्यक्तिगत रूप से राज्य को बनाए रखने के लिए प्रॉक्सी का उपयोग करता हूं, घटक फिर प्रोपर बदलावों की जांच कर सकता है और फिर अपडेट कर सकता है। बहुत कुशलता से काम करने लगता है। उदाहरण के लिए, मेरे सभी घटकों को एक प्रॉक्सी द्वारा नियंत्रित किया जाता है, यह प्रॉक्सी SessionStorage द्वारा समर्थित है, इसलिए भले ही उपयोगकर्ता अपने वेबपेज को ताज़ा करता है, यहां तक ​​कि ड्रॉपडाउन की स्थिति आदि को बनाए रखा जाता है। IOW: मैं राज्य का उपयोग बिल्कुल नहीं करता, सब कुछ रंगमंच की सामग्री के साथ नियंत्रित होता है।
कीथ


5

आप इस बात का फायदा उठाकर सामान्य हुक का उपयोग कर सकते हैं कि जेएसटी कोड में रिएलिटी बूलियन प्रिंट नहीं करता है।

// create a hook
const [forceRerender, setForceRerender] = React.useState(true);

// ...put this line where you want to force a rerender
setForceRerender(!forceRerender);

// ...make sure that {forceRerender} is "visible" in your js code
// ({forceRerender} will not actually be visible since booleans are
// not printed, but updating its value will nonetheless force a
// rerender)
return (
  <div>{forceRerender}</div>
)


1
इस मामले में, जब सेटबुलियन दो बार बच्चों को बदलता है तो React.useEffect अपडेट को पुन: लागू नहीं कर सकता है।
अल्मा

जहां तक ​​मैं समझता हूं कि यह प्रतिक्रिया हर बूलियन अपडेट को पृष्ठ को फिर से प्रस्तुत करने के लिए एक कारण के रूप में मानती है, भले ही बूलियन फिर से जल्दी से वापस आ जाए। उस ने कहा, रिएक्ट बेशक एक मानक नहीं है, और वास्तव में यह इस उदाहरण में कैसे काम करता है अपरिभाषित है और परिवर्तन के अधीन है।
फर्जी

1
मुझे नहीं पता। किसी कारण से मैं इस संस्करण से आकर्षित हुआ हूं। यह मुझे गुदगुदी :-)। जिसके अलावा, यह शुद्ध लगता है। कुछ ऐसा बदला कि मेरा JSX निर्भर करता है, इसलिए मैं रेंडर करता हूं। यह अजेयता उस IMO से अलग नहीं होती है।
एड्रियन बार्थोलोम्यू

4

संभावित विकल्प केवल विशिष्ट घटक का उपयोग करके अद्यतन को बाध्य करना है key। घटक के प्रतिपादन के लिए कुंजी को अद्यतन करना (जो पहले अपडेट करने में विफल रहा)

उदाहरण के लिए:

const [tableKey, setTableKey] = useState(1);
...

useEffect(() => {
    ...
    setTableKey(tableKey + 1);
}, [tableData]);

...
<DataTable
    key={tableKey}
    data={tableData}/>

1
यह अक्सर सबसे साफ तरीका है अगर राज्य मूल्य और पुन: रेंडर करने की आवश्यकता के बीच 1: 1 संबंध है।
jaimefps

1
यह एक आसान उपाय है
प्रियंका V


3

एक पंक्ति समाधान:

const useForceUpdate = () => useState()[1];

useState मानों की एक जोड़ी लौटाता है: वर्तमान स्थिति और एक फ़ंक्शन जो इसे अपडेट करता है - राज्य और सेटर , यहां हम पुन: रेंडर करने के लिए केवल सेटर का उपयोग कर रहे हैं।


2

मेरी भिन्नता किसी वस्तु के माध्यम forceUpdateसे नहीं counterबल्कि एक वस्तु के माध्यम से होती है:

// Emulates `forceUpdate()`
const [unusedState, setUnusedState] = useState()
const forceUpdate = useCallback(() => setUnusedState({}), [])

क्योंकि {} !== {}हर बार।


क्या है useCallback()? वह कहां से आया है? उफ़। मैं इसे अभी देख रहा हूँ ...
zipzit

2

यह 3 बार घटकों के आधार पर रेंडर करेगा (समान तत्वों के साथ सरणियाँ बराबर नहीं हैं):

const [msg, setMsg] = useState([""])

setMsg(["test"])
setMsg(["test"])
setMsg(["test"])

1
मेरा मानना ​​है कि आपको किसी आइटम को सरणी में रखने की आवश्यकता नहीं है। एक खाली सरणी कड़ाई से वस्तुओं की तरह, एक अलग खाली सरणी के बराबर नहीं होती है।
Qwerty

हाँ, बस यह दिखाना चाहता था कि डेटा पास करने के तरीके के रूप में
Janek Olszak

2

react-tidyएक कस्टम हुक है कि सिर्फ करने के लिए बुलाया useRefresh:

import React from 'react'
import {useRefresh} from 'react-tidy'

function App() {
  const refresh = useRefresh()
  return (
    <p>
      The time is {new Date()} <button onClick={refresh}>Refresh</button>
    </p>
  )
}

इस हुक के बारे में और जानें

अस्वीकरण मैं इस पुस्तकालय का लेखक हूं।


1

नियमित रिएक्ट क्लास आधारित घटकों के लिए, इस URL forceUpdateपर एपीआई के लिए रिएक्ट डॉक्स देखें । डॉक्स का उल्लेख है कि:

आम तौर पर आपको बलप्रयोग () के सभी उपयोगों से बचने की कोशिश करनी चाहिए और केवल इस से पढ़ा जाना चाहिए। यह और रेंडर में यह। ()

हालाँकि, यह डॉक्स में भी उल्लिखित है:

यदि आपकी रेंडर () विधि कुछ अन्य डेटा पर निर्भर करती है, तो आप React को बता सकते हैं कि कंपोनेंट को फोर्स यूपीडेट () कहकर पुन: रेंडरिंग की आवश्यकता है।

इसलिए, यद्यपि उपयोग करने के मामले forceUpdateदुर्लभ हो सकते हैं, और मैंने इसका कभी उपयोग नहीं किया है, हालांकि मैंने इसे कुछ विरासत कॉर्पोरेट परियोजनाओं में अन्य डेवलपर्स द्वारा उपयोग किया है जिन्हें मैंने काम किया है।

इसलिए, कार्यात्मक घटकों के लिए समान कार्यक्षमता के लिए, इस URL पर HOOKS के लिए रिएक्ट डॉक्स देखें । ऊपर दिए गए URL के अनुसार, कोई व्यक्ति “FunctReducer” हुक का उपयोग forceUpdateकार्यात्मक घटकों के लिए एक कार्यक्षमता प्रदान करने के लिए कर सकता है ।

एक कार्य कोड नमूना that does not use state or propsनीचे दिया गया है, जो इस URL पर CodeSandbox पर भी उपलब्ध है

import React, { useReducer, useRef } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  // Use the useRef hook to store a mutable value inside a functional component for the counter
  let countref = useRef(0);

  const [, forceUpdate] = useReducer(x => x + 1, 0);

  function handleClick() {
    countref.current++;
    console.log("Count = ", countref.current);
    forceUpdate(); // If you comment this out, the date and count in the screen will not be updated
  }

  return (
    <div className="App">
      <h1> {new Date().toLocaleString()} </h1>
      <h2>You clicked {countref.current} times</h2>
      <button
        onClick={() => {
          handleClick();
        }}
      >
        ClickToUpdateDateAndCount
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

नोट: इस URL पर यूज़स्ट्रेट हुक (उपयोगरेड्यूसर के बजाय) का उपयोग करते हुए एक वैकल्पिक दृष्टिकोण भी उपलब्ध है ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.