प्रतिक्रिया - रेंडर करने के लिए फंक्शन कंपोनेंट को कैसे बाध्य करें?


99

मेरे पास एक फ़ंक्शन घटक है, और मैं इसे फिर से प्रस्तुत करने के लिए मजबूर करना चाहता हूं।

ऐसा मैं किस प्रकार करूं?
चूंकि कोई उदाहरण नहीं है this, इसलिए मैं फोन नहीं कर सकता this.forceUpdate()


1
नहीं, एक स्टेटलेस कंपोनेंट में कोई स्टेट नहीं होता है। इसके बजाय एक वर्ग का उपयोग करें
TryingToImprove

3
क्या आप वास्तव में "स्टेटलेस घटक " और "कार्यात्मक घटक" नहीं हैं ?
क्रिस

3
एक स्टेटलेस कंपोनेंट को अपडेट करने के लिए, प्रॉपर को बदलने की जरूरत है।
फंगसुन्थ्रैक्स

1
प्रॉप्स के बगल में आप हुक यूज़स्ट्रेट का उपयोग कर सकते हैं, और घटकों को फिर से प्रस्तुत किया जाएगा जब यह बदल जाएगा
हामिद शोजा

जवाबों:


152

Hook आप अब रिएक्ट हुक का उपयोग कर सकते हैं

प्रतिक्रिया हुक का उपयोग करते हुए, अब आप useState()अपने फ़ंक्शन घटक में कॉल कर सकते हैं ।

useState() 2 चीजों की एक सरणी लौटाएगा:

  1. एक मान, वर्तमान स्थिति का प्रतिनिधित्व करता है।
  2. इसका सेटर। मान अपडेट करने के लिए इसका उपयोग करें।

इसके सेटर द्वारा मूल्य को अपडेट करना आपके फ़ंक्शन घटक को फिर से प्रस्तुत करने के लिए बाध्य करेगा ,
जैसे forceUpdate:

import React, { useState } from 'react';

//create your forceUpdate hook
function useForceUpdate(){
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => value + 1); // update the state to force render
}

function MyComponent() {
    // call your hook here
    const forceUpdate = useForceUpdate();
    
    return (
        <div>
            {/*Clicking on the button will force to re-render like force update does */}
            <button onClick={forceUpdate}>
                Click to re-render
            </button>
        </div>
    );
}

आप यहां एक डेमो पा सकते हैं

ऊपर दिया गया घटक कस्टम हुक फ़ंक्शन ( useForceUpdate) का उपयोग करता है जो प्रतिक्रिया स्थिति हुक का उपयोग करता है useState। यह घटक के राज्य के मूल्य में वृद्धि करता है और इस प्रकार घटक को फिर से प्रस्तुत करने के लिए रिएक्ट बताता है।

संपादित करें

इस उत्तर के पुराने संस्करण में, स्निपेट ने बूलियन मूल्य का उपयोग किया, और इसमें टॉगल किया forceUpdate()। अब जब मैंने अपना उत्तर संपादित कर लिया है, तो स्निपेट बूलियन के बजाय एक संख्या का उपयोग करता है।

क्यों ? (आप मुझसे पूछेंगे)

क्योंकि एक बार मेरे साथ ऐसा हुआ forceUpdate()था कि मुझे दो अलग-अलग घटनाओं से बाद में दो बार बुलाया गया था, और इस प्रकार यह मूल स्थिति पर बूलियन मान को रीसेट कर रहा था, और घटक कभी भी प्रदान नहीं किया गया था।

ऐसा इसलिए है क्योंकि यहां के useStateसेटर ( setValueयहां), Reactपिछले राज्य की तुलना नए के साथ करते हैं, और केवल तभी प्रस्तुत करते हैं जब राज्य अलग हो।


5
उस पेज पर कुछ भी नहीं है हुक का उपयोग करने के बारे में कोई जानकारी है कॉल करने के लिए forceUpdate
jdelman

1
अभी के लिए, आप सही हैं यह बेहतर है, क्योंकि, अभी भी सख्त हुक जारी नहीं किए गए हैं, आप अभी भी इसे बीटा में उपयोग कर सकते हैं। लेकिन एक बार जब वे रिहा हो जाते हैं, तो कोई कारण नहीं है कि कक्षा का घटक बेहतर होगा। हुक का उपयोग करना क्लास कंपोनेंट की तुलना में कोड क्लीनर बनाता है, जैसा कि नीचे दिए गए वीडियो में दिया गया है। वैसे भी, सवाल यह है कि क्या यह संभव है। उत्तर अब हुक के कारण "नहीं" से "हां" में बदल जाता है। youtube.com/watch?v=wXLf18DsV-I
Yairopro

1
हाय @ डेंटीस्मिथ "शीर्ष स्तर" से, इसका मतलब है कि हुक को किसी शर्त या लूप के अंदर से नहीं बुलाया जाना चाहिए, जैसा कि आपने कहा। लेकिन मैं आपको बता सकता हूं कि आप उन्हें किसी अन्य फ़ंक्शन के अंदर से कॉल कर सकते हैं। और इसका मतलब है कि एक कस्टम हुक बनाना। डैन अब्रामोव, जैसा कि वह रिएक्ट में रिएक्ट हुक प्रस्तुत करता है, स्पष्ट रूप से प्रदर्शित करता है कि कार्यात्मक घटकों के बीच तर्क साझा करने का यह सबसे साफ और सबसे अच्छा तरीका है: youtu.be/dpw9EHDh2bM?t=2n3
Yairopro

1
"रेंडर करने के लिए मजबूर करने के लिए" किसी भी राज्य को टॉगल करने की कोई आवश्यकता नहीं है। आप एक गलत धारणा बनाते हैं, जिसे प्रतिक्रिया देने के लिए रिएक्ट "तुलना" प्रचलित और अगले राज्य मानों की आवश्यकता है कि क्या इसे फिर से प्रस्तुत करने की आवश्यकता है। जबकि यह निश्चित रूप से नहीं करता है।
मेन्ड्रे

1
@meandre हाँ यह निश्चित रूप से तुलना करता है। हम useStateहुक के बारे में बात कर रहे हैं , न कि वर्ग ' setStateजो वास्तव में एक तुलना नहीं करता है (जब तक आप को लागू नहीं करना चाहिए विधि)। वही डेमो देखें जो मैंने पोस्ट किया था, लेकिन setStateइसके लिए इस्तेमाल किए जाने वाले एक स्थिर मूल्य के साथ , यह फिर से रेंडर नहीं करता है: codeandbox.io/s/determined-rubin-8598l
Yairopro

49

अद्यतन प्रतिक्रिया v16.8 (16 फरवरी 2019 realease)

चूंकि 16.8 हुक के साथ जारी किया गया था , इसलिए फ़ंक्शन घटकों में अब लगातार पकड़ रखने की क्षमता है state। कि क्षमता के साथ अब आप कर सकते हैं की नकल एक forceUpdate:

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


प्रतिक्रिया से पहले 16.8.0

नहीं, आप नहीं कर सकते, राज्य-कम फ़ंक्शन घटक केवल सामान्य हैं functionsजो रिटर्न करते हैं jsx, आपके पास रिएक्ट जीवन चक्र विधियों तक कोई पहुंच नहीं है क्योंकि आप इसमें से विस्तार नहीं कर रहे हैं React.Component

फ़ंक्शन-घटक को renderवर्ग घटकों के विधि भाग के रूप में सोचें ।


आप कर सकते हैं। इसके लिए आने वाले रंगमंच की सामग्री को बदल दें
मारीना ज़ेके

6
वह फिर से रेंडर करने के लिए मजबूर नहीं कर रहा है, यह सिर्फ एक सामान्य रेंडर है। जब आप रेंडरिंग को बाध्य करना चाहते हैं , तो यह आमतौर पर एक ऐसा मामला होता है जब आप रेंडर विधि को चलाना चाहते हैं जब इसे चलाने के लिए डिज़ाइन नहीं किया गया था, उदाहरण के लिए जब कोई नया propsया stateपरिवर्तन नहीं होता है। आप रेंडर फ़ंक्शन को बाध्य नहीं कर सकते क्योंकि renderस्टेटलेस घटकों पर कोई फ़ंक्शन नहीं है । स्टेटलेस कंपोनेंट्स नहीं हैं कि extends React.Componentवे सिर्फ सादे फंक्शन हैं जो रिटर्न करते हैं jsx
सागिव बीजी

"जब आपको किसी अपडेट के लिए मजबूर करने की आवश्यकता होती है, तो आप शायद कुछ गलत कर रहे हों" के लिए प्रॉप्स - मुझे पता था कि ऐसा ही था, लेकिन इसने मुझे मेरे उपयोग हुक पर एक और अच्छा नज़र डालने के लिए प्रेरित किया।
मेथोडिस्ट जूल

13

आधिकारिक अक्सर पूछे जाने वाले प्रश्न ( https://reactjs.org/docs/hooks-faq.html#is-there-something-like-forceupdate ) अब इस तरह से अनुशंसा करता है यदि आपको वास्तव में करने की आवश्यकता है:

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

  function handleClick() {
    forceUpdate();
  }

वैसे मैं इसे कभी नहीं जानता था
चेरिथ जयसंका

11
और आप अपने कोड 7 बाइट्स को छोटा बना सकते हैं और अप्रयुक्त चर नहीं बना सकते हैं:const [, forceUpdate] = useReducer(x => x + 1, 0);
कोंस्टेंटिन स्मोलिनिन

8

मैंने अपनी प्रतिक्रिया कार्यात्मक घटकों को प्रस्तुत करने के लिए बल -प्रयोग-अद्यतन नामक एक तृतीय पक्ष पुस्तकालय का उपयोग किया । आकर्षण की तरह काम किया। बस अपनी परियोजना में पैकेज का उपयोग करें और इस तरह का उपयोग करें।

import useForceUpdate from 'use-force-update';

const MyButton = () => {

  const forceUpdate = useForceUpdate();

  const handleClick = () => {
    alert('I will re-render now.');
    forceUpdate();
  };

  return <button onClick={handleClick} />;
};

3
आपको एक क्लिक बचाने के लिए - अन्य उत्तरों में बताए अनुसार useForceUpdateउपयोग करता useCallbackहै। यह दायित्व आपको कुछ कीस्ट्रोक्स से बचाने के लिए सिर्फ एक उपयोगिता है।
asyncwait

1
ओह धन्यवाद। मुझे नहीं पता था। :)
चरिथ जयसंका

6

अस्वीकरण: समस्या के प्रति उत्तर नहीं।

यहां एक महत्वपूर्ण नोट छोड़ना:

यदि आप एक स्टेटलेस कंपोनेंट को बाध्य करने की कोशिश कर रहे हैं, तो संभावना है कि आपके डिजाइन में कुछ गड़बड़ है।

निम्नलिखित मामलों पर विचार करें:

  1. एक बच्चे के घटक के लिए एक सेटर (सेटस्टेट) पास करें जो राज्य को बदल सकता है और मूल घटक को फिर से प्रस्तुत करने का कारण बन सकता है।
  2. राज्य को ऊपर उठाने पर विचार करें
  3. उस स्थिति को अपने Redux स्टोर में रखने पर विचार करें, जो स्वचालित रूप से जुड़े घटकों पर फिर से रेंडर करने के लिए मजबूर कर सकता है।

1
मेरे पास एक ऐसा मामला है जहां मुझे घटक अद्यतनों को अक्षम करने की आवश्यकता है और जब मैं चाहता हूं तब इसे बाध्य करें (एक चलती शासक है, यह अद्यतन हर चाल का मूल्य है और अद्यतन एक चंचल व्यवहार का कारण बनता है)। इसलिए मैंने इस घटक पर कक्षाओं का उपयोग करने का निर्णय लिया है और मैं सलाह देता हूं कि सभी घटकों को रेंडर व्यवहार पर एक गहन नियंत्रण की आवश्यकता है, जो कक्षाओं में किया जाना चाहिए, क्योंकि वर्तमान में हुक इस व्यवहार पर एक अच्छा नियंत्रण प्रदान नहीं करते हैं। (वर्तमान प्रतिक्रिया संस्करण 16.12 है)
माइकल वालेस

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

वास्तविक दुनिया में, इसके लिए उपयोग हैं। कुछ भी कभी भी सही नहीं है, और यदि आप कभी भी दरवाजे से सॉफ्टवेयर बाहर निकालना चाहते हैं, तो आप बेहतर जानते हैं कि चीजों को कैसे करना है जब कोई और उन्हें ऊपर ले जाता है।
ब्रेन2000

1

यह स्पष्ट रूप से हुक का उपयोग किए बिना किया जा सकता है, बशर्ते आप अपने घटक और स्टेट को किसी घटक के मूल घटक में जोड़ दें:

const ParentComponent = props => {
  const [updateNow, setUpdateNow] = useState(true)

  const updateFunc = () => {
    setUpdateNow(!updateNow)
  }

  const MyComponent = props => {
    return (<div> .... </div>)
  }

  const MyButtonComponent = props => {
    return (<div> <input type="button" onClick={props.updateFunc} />.... </div>)
  }

  return (
    <div> 
      <MyComponent updateMe={updateNow} />
      <MyButtonComponent updateFunc={updateFunc}/>
    </div>
  )
}

1

स्वीकृत उत्तर अच्छा है। बस इसे समझना आसान है।

उदाहरण घटक:

export default function MyComponent(props) {

    const [updateView, setUpdateView] = useState(0);

    return (
        <>
            <span style={{ display: "none" }}>{updateView}</span>
        </>
    );
}

नीचे दिए गए कोड को फिर से रेंडर करने के लिए मजबूर करने के लिए:

setUpdateView((updateView) => ++updateView);

-1

इनमें से किसी ने भी मुझे संतोषजनक जवाब नहीं दिया, इसलिए अंत में मुझे वही मिला जो मुझे keyप्रोप, यूज़ रीफ और कुछ रैंडम आईडी जनरेटर के साथ चाहिए था shortid

मूल रूप से, मैं चाहता था कि कुछ चैट एप्लिकेशन पहली बार किसी को ऐप खोलने के लिए बाहर करें। तो, मुझे इस बात पर पूर्ण नियंत्रण की आवश्यकता थी कि कब और क्या जवाबों को async प्रतीक्षा के साथ अद्यतन किया जाए।

उदाहरण कोड:

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// ... your JSX functional component, import shortid somewhere

const [render, rerender] = useState(shortid.generate())

const messageList = useRef([
    new Message({id: 1, message: "Hi, let's get started!"})
])

useEffect(()=>{
    await sleep(500)
    messageList.current.push(new Message({id: 1, message: "What's your name?"}))
    // ... more stuff
    // now trigger the update
    rerender(shortid.generate())
}, [])

// only the component with the right render key will update itself, the others will stay as is and won't rerender.
return <div key={render}>{messageList.current}</div> 

वास्तव में इसने मुझे एक चैट संदेश की तरह रोल करने की अनुमति दी।

const waitChat = async (ms) => {
    let text = "."
    for (let i = 0; i < ms; i += 200) {
        if (messageList.current[messageList.current.length - 1].id === 100) {
            messageList.current = messageList.current.filter(({id}) => id !== 100)
        }
        messageList.current.push(new Message({
            id: 100,
            message: text
        }))
        if (text.length === 3) {
            text = "."
        } else {
            text += "."
        }
        rerender(shortid.generate())
        await sleep(200)
    }
    if (messageList.current[messageList.current.length - 1].id === 100) {
        messageList.current = messageList.current.filter(({id}) => id !== 100)
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.