एक घटक की अद्यतन शैली को React.js में चालू करें


133

मैंने रिएक्ट में एक घटक बनाया है जो लंबन प्रभाव बनाने के लिए विंडो स्क्रॉल पर अपनी शैली को अपडेट करने वाला है।

घटक renderविधि इस प्रकार दिखती है:

  function() {
    let style = { transform: 'translateY(0px)' };

    window.addEventListener('scroll', (event) => {
      let scrollTop = event.srcElement.body.scrollTop,
          itemTranslate = Math.min(0, scrollTop/3 - 60);

      style.transform = 'translateY(' + itemTranslate + 'px)');
    });

    return (
      <div style={style}></div>
    );
  }

यह काम नहीं करता है क्योंकि रिएक्ट को पता नहीं है कि घटक बदल गया है, और इसलिए घटक को फिर से प्रस्तुत नहीं किया गया है।

मैंने itemTranslateकंपोनेंट की स्थिति में, और setStateस्क्रॉल कॉलबैक में कॉलिंग का मान रखने की कोशिश की है । हालाँकि, यह स्क्रॉलिंग को अनुपयोगी बनाता है क्योंकि यह बहुत धीमा है।

यह कैसे करना है पर कोई सुझाव?


9
रेंडर मेथड के अंदर कभी भी एक्सटर्नल इवेंट हैंडलर को न बांधें। रेंडरिंग तरीके (और किसी भी अन्य कस्टम तरीके जिसे आप renderएक ही थ्रेड से कॉल करते हैं) केवल वास्तविक डोम को रिएक्ट में रेंडर करने / अपडेट करने से संबंधित तर्क से संबंधित होना चाहिए। इसके बजाय, जैसा कि नीचे @AustinGreco द्वारा दिखाया गया है, आपको अपने ईवेंट बाइंडिंग को बनाने और निकालने के लिए दिए गए रिएक्ट जीवनचक्र के तरीकों का उपयोग करना चाहिए। यह इसे घटक के अंदर स्व-सम्‍मिलित करता है और सुनिश्चित करता है कि इवेंट बाइंडिंग को हटा दिया गया है या नहीं, यह सुनिश्चित करने से कोई लीक नहीं होता है।
माइक ड्राइवर

जवाबों:


232

आपको श्रोता को componentDidMountउस तरह से बांधना चाहिए , जिस तरह से यह केवल एक बार बनाया गया है। आपको शैली को राज्य में संग्रहीत करने में सक्षम होना चाहिए, श्रोता शायद प्रदर्शन के मुद्दों का कारण था।

कुछ इस तरह:

componentDidMount: function() {
    window.addEventListener('scroll', this.handleScroll);
},

componentWillUnmount: function() {
    window.removeEventListener('scroll', this.handleScroll);
},

handleScroll: function(event) {
    let scrollTop = event.srcElement.body.scrollTop,
        itemTranslate = Math.min(0, scrollTop/3 - 60);

    this.setState({
      transform: itemTranslate
    });
},

26
मैंने पाया कि एनीमेशन के लिए स्क्रॉल इवेंट के अंदर setState'ing तड़का हुआ है। मुझे मैन्युअल रूप से रिफ का उपयोग करके घटकों की शैली निर्धारित करनी थी।
रयान रो

1
हैंडल के अंदर "इस" को क्या इंगित किया जाएगा? मेरे मामले में यह "विंडो" है घटक नहीं। मैं एक पैरामीटर के रूप में घटक को समाप्त करता हूं
युजी

10
@ ओयजी आप कंस्ट्रक्टर में इसे बांधकर कंपोनेंट पास करने की जरूरत से बच सकते हैं: this.handleScroll = this.handleScroll.bind(this)इसे handleScrollविंडो के बजाय कंपोनेंट के भीतर बांध देंगे ।
मैट पैरीला

1
ध्यान दें कि फ़ायरफ़ॉक्स में srcElement उपलब्ध नहीं है।
पॉलिन ट्रोगनॉन

2
मेरे लिए काम नहीं किया, लेकिन क्या किया था स्थापित करने के लिए ScrollTopevent.target.scrollingElement.scrollTop
जॉर्ज

31

आप onScrollप्रतिक्रिया तत्व पर घटना के लिए एक समारोह पारित कर सकते हैं : https://facebook.github.io/react/docs/events.html#ui-events

<ScrollableComponent
 onScroll={this.handleScroll}
/>

एक अन्य उत्तर जो समान है: https://stackoverflow.com/a/36207913/1255973


5
क्या इस विधि के विरुद्ध कोई लाभ / कमियां हैं मैन्युअल रूप से विंडो तत्व @AustinGreco में इवेंट श्रोता को जोड़ने के लिए?
डेनिस

2
@ डेनिस एक लाभ यह है कि आपको ईवेंट श्रोताओं को मैन्युअल रूप से जोड़ना / निकालना नहीं है। हालांकि यह एक सरल उदाहरण हो सकता है यदि आप मैन्युअल रूप से कई एप्लिकेशन श्रोताओं को अपने एप्लिकेशन पर मैन्युअल रूप से प्रबंधित करते हैं, तो अपडेट पर उन्हें ठीक से भूलना भूल जाते हैं, जिससे मेमोरी बग हो सकते हैं। यदि संभव हो तो मैं हमेशा अंतर्निहित संस्करण का उपयोग करूंगा।
एफ लेक्सचा

4
यह ध्यान देने योग्य है कि यह एक स्क्रॉल हैंडलर को घटक में ही जोड़ता है, न कि खिड़की पर, जो कि बहुत अलग चीज है। @ डेनिस onScroll का लाभ यह है कि यह अधिक क्रॉस-ब्राउज़र और अधिक प्रदर्शन करने वाला है। यदि आप इसका उपयोग कर सकते हैं तो आपको संभवतः करना चाहिए, लेकिन ओपी के लिए एक जैसे मामलों में यह उपयोगी नहीं हो सकता है
ब्यूउ

20

एक उत्तरदायी नावबार बनाने के लिए मेरा समाधान (स्थिति: 'रिश्तेदार' जब स्क्रॉल नहीं किया जाता है और स्क्रॉल करते समय तय किया जाता है और पृष्ठ के शीर्ष पर नहीं)

componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
}

componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
}
handleScroll(event) {
    if (window.scrollY === 0 && this.state.scrolling === true) {
        this.setState({scrolling: false});
    }
    else if (window.scrollY !== 0 && this.state.scrolling !== true) {
        this.setState({scrolling: true});
    }
}
    <Navbar
            style={{color: '#06DCD6', borderWidth: 0, position: this.state.scrolling ? 'fixed' : 'relative', top: 0, width: '100vw', zIndex: 1}}
        >

मेरे लिए कोई प्रदर्शन समस्या नहीं है।


आप एक नकली हेडर का भी उपयोग कर सकते हैं जो अनिवार्य रूप से सिर्फ एक प्लेसहोल्डर है। तो आपको अपना निश्चित हेडर मिल गया है और उसके नीचे आपको अपना प्लेसहोल्डर नकली ले लेने वाला पद मिल गया है: रिश्तेदार।
रॉबिन्स_

कोई प्रदर्शन समस्या नहीं है क्योंकि यह प्रश्न में लंबन चुनौती को संबोधित नहीं करता है।
जुआनिटोगन

19

यहाँ किसी को भी मदद करने के लिए, जिन्होंने ऑस्टिन के उत्तर का उपयोग करते समय अशिष्ट व्यवहार / प्रदर्शन के मुद्दों पर ध्यान दिया, और टिप्पणियों में उल्लिखित रेफरी का उपयोग करके एक उदाहरण चाहते हैं, यहां एक उदाहरण है जो मैं एक स्क्रॉल अप / डाउन आइकन के लिए एक वर्ग को टॉगल करने के लिए उपयोग कर रहा था:

रेंडर विधि में:

<i ref={(ref) => this.scrollIcon = ref} className="fa fa-2x fa-chevron-down"></i>

हैंडलर विधि में:

if (this.scrollIcon !== null) {
  if(($(document).scrollTop() + $(window).height() / 2) > ($('body').height() / 2)){
    $(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-up');
  }else{
    $(this.scrollIcon).attr('class', 'fa fa-2x fa-chevron-down');
  }
}

और अपने संचालकों को उसी तरह जोड़ें / हटाएं जैसे ऑस्टिन ने उल्लेख किया था:

componentDidMount(){
  window.addEventListener('scroll', this.handleScroll);
},
componentWillUnmount(){
  window.removeEventListener('scroll', this.handleScroll);
},

रेफरी पर डॉक्स ।


4
आपने मेरा दिन बचाया! अपडेट करने के लिए, आपको वास्तव में इस बिंदु पर क्लासनाम को संशोधित करने के लिए jquery का उपयोग करने की आवश्यकता नहीं है, क्योंकि यह पहले से ही एक मूल डोम तत्व है। तो आप बस कर सकते हैं this.scrollIcon.className = whatever-you-want
दक्षिणपूर्वी

2
हालांकि यह समाधान रिएक्ट एनकैप्सुलेशन को तोड़ता है, हालांकि मैं अभी भी इस तरह के आस-पास के व्यवहार के बिना निश्चित नहीं हूं - शायद एक विवादित स्क्रॉल घटना (शायद 200-250 एमएस पर) यहां एक समाधान होगा
जॉर्डन

नोप डेब्यू स्क्रोल इवेंट केवल स्क्रॉलिंग स्मूथ (गैर-अवरोधक अर्थ में) बनाने में मदद करता है, लेकिन डोम में आवेदन करने के लिए अपडेट के लिए 500 सेकंड से लेकर सेकंड तक का समय लगता है: /
जॉर्डन

मैंने इस समाधान का उपयोग किया, साथ ही +1। मैं मानता हूँ कि आपको jQuery की आवश्यकता नहीं है: बस उपयोग करें classNameया classList। इसके अलावा, मुझे ज़रूरत नहीं थीwindow.addEventListener() : मैंने सिर्फ रिएक्ट का इस्तेमाल किया था onScroll, और यह उतना ही तेज़ है, जब तक कि आप प्रॉप्स / स्टेट को अपडेट नहीं करते हैं!
बेंजामिन

13

मैंने पाया कि मैं इवेंट श्रोता को तब तक सफलतापूर्वक नहीं जोड़ सकता जब तक कि मैं ऐसा नहीं करता।

componentDidMount = () => {
    window.addEventListener('scroll', this.handleScroll, true);
},

यह काम कर रहा है। लेकिन क्या आप यह जान सकते हैं कि हमें इस श्रोता के लिए सच्चा बूलियन क्यों पारित करना है।
शाह चैतन्य

2
W3schools से: [ w3schools.com/jsref/met_document_addeventlistener.asp] userCapture : वैकल्पिक। एक बूलियन मान जो निर्दिष्ट करता है कि क्या घटना को कैप्चरिंग में या बबलिंग चरण में निष्पादित किया जाना चाहिए। संभावित मान: सत्य - ईवेंट हैंडलर कैप्चरिंग चरण गलत-डिफ़ॉल्ट में निष्पादित होता है। ईवेंट हैंडलर
बुबलिंग

12

का उपयोग कर एक उदाहरण classnames , प्रतिक्रिया हुक useEffect , useState और स्टाइल-jsx :

import classNames from 'classnames'
import { useEffect, useState } from 'react'

const Header = _ => {
  const [ scrolled, setScrolled ] = useState()
  const classes = classNames('header', {
    scrolled: scrolled,
  })
  useEffect(_ => {
    const handleScroll = _ => { 
      if (window.pageYOffset > 1) {
        setScrolled(true)
      } else {
        setScrolled(false)
      }
    }
    window.addEventListener('scroll', handleScroll)
    return _ => {
      window.removeEventListener('scroll', handleScroll)
    }
  }, [])
  return (
    <header className={classes}>
      <h1>Your website</h1>
      <style jsx>{`
        .header {
          transition: background-color .2s;
        }
        .header.scrolled {
          background-color: rgba(0, 0, 0, .1);
        }
      `}</style>
    </header>
  )
}
export default Header

1
ध्यान दें कि क्योंकि इस उपयोग में कोई दूसरा तर्क नहीं है, यह हर एक बार हैडर रेंडर करता है।
जॉर्डन

2
@ जोर्डन तुम सही हो! यह लिखने में मेरी गलती है। मैं उत्तर संपादित करूँगा। आपका बहुत बहुत धन्यवाद।
giovannipds

8

हुक के साथ

import React, { useEffect, useState } from 'react';

function MyApp () {

  const [offset, setOffset] = useState(0);

  useEffect(() => {
    window.onscroll = () => {
      setOffset(window.pageYOffset)
    }
  }, []);

  console.log(offset); 
};

बिल्कुल वही जो मुझे चाहिए था। धन्यवाद!
आबक्विस्मिथ

यह अब तक का सबसे प्रभावी और सुरुचिपूर्ण जवाब है। इसके लिए धन्यवाद।
चिगोजी ओरुंटा

इसके लिए अधिक ध्यान देने की जरूरत है, एकदम सही।
एंडर्स किटसन

6

उपयोग के लिए फंक्शन घटक का उदाहरण

नोट : आपको उपयोग में "क्लीन अप" फ़ंक्शन को वापस करके इवेंट श्रोता को निकालने की आवश्यकता है। यदि आप नहीं करते हैं, तो हर बार घटक अपडेट होने पर आपके पास एक अतिरिक्त विंडो स्क्रॉल श्रोता होगा।

import React, { useState, useEffect } from "react"

const ScrollingElement = () => {
  const [scrollY, setScrollY] = useState(0);

  function logit() {
    setScrollY(window.pageYOffset);
  }

  useEffect(() => {
    function watchScroll() {
      window.addEventListener("scroll", logit);
    }
    watchScroll();
    // Remove listener (like componentWillUnmount)
    return () => {
      window.removeEventListener("scroll", logit);
    };
  }, []);

  return (
    <div className="App">
      <div className="fixed-center">Scroll position: {scrollY}px</div>
    </div>
  );
}

ध्यान दें कि क्योंकि इस उपयोग में कोई दूसरा तर्क नहीं है, यह हर बार घटक रेंडर करने पर चलेगा।
जॉर्डन

अच्छी बात। क्या हमें उपयोग कॉल के लिए एक खाली सरणी जोड़ना चाहिए?
रिचर्ड

यही मैं करूंगा :)
जॉर्डन

5

यदि आप जिस चीज में रुचि रखते हैं, वह एक बच्चा घटक है जो स्क्रॉल कर रहा है, तो यह उदाहरण मदद का हो सकता है: https://codepen.io/JohnReynolds57/pen/NLNOyO?editors=0011

class ScrollAwareDiv extends React.Component {
  constructor(props) {
    super(props)
    this.myRef = React.createRef()
    this.state = {scrollTop: 0}
  }

  onScroll = () => {
     const scrollTop = this.myRef.current.scrollTop
     console.log(`myRef.scrollTop: ${scrollTop}`)
     this.setState({
        scrollTop: scrollTop
     })
  }

  render() {
    const {
      scrollTop
    } = this.state
    return (
      <div
         ref={this.myRef}
         onScroll={this.onScroll}
         style={{
           border: '1px solid black',
           width: '600px',
           height: '100px',
           overflow: 'scroll',
         }} >
        <p>This demonstrates how to get the scrollTop position within a scrollable 
           react component.</p>
        <p>ScrollTop is {scrollTop}</p>
     </div>
    )
  }
}

1

मैंने CSS चरों के उपयोग और संशोधन के माध्यम से समस्या को हल किया। इस तरह मुझे घटक स्थिति को संशोधित करने की आवश्यकता नहीं है जो प्रदर्शन के मुद्दों का कारण बनता है।

index.css

:root {
  --navbar-background-color: rgba(95,108,255,1);
}

Navbar.jsx

import React, { Component } from 'react';
import styles from './Navbar.module.css';

class Navbar extends Component {

    documentStyle = document.documentElement.style;
    initalNavbarBackgroundColor = 'rgba(95, 108, 255, 1)';
    scrolledNavbarBackgroundColor = 'rgba(95, 108, 255, .7)';

    handleScroll = () => {
        if (window.scrollY === 0) {
            this.documentStyle.setProperty('--navbar-background-color', this.initalNavbarBackgroundColor);
        } else {
            this.documentStyle.setProperty('--navbar-background-color', this.scrolledNavbarBackgroundColor);
        }
    }

    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll);
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll);
    }

    render () {
        return (
            <nav className={styles.Navbar}>
                <a href="/">Home</a>
                <a href="#about">About</a>
            </nav>
        );
    }
};

export default Navbar;

Navbar.module.css

.Navbar {
    background: var(--navbar-background-color);
}

1

मेरी शर्त यहाँ हल करने के लिए नए हुक के साथ फ़ंक्शन घटकों का उपयोग कर रही है, लेकिन useEffectपिछले उत्तरों की तरह उपयोग करने के बजाय , मुझे लगता है कि useLayoutEffectएक महत्वपूर्ण कारण के लिए सही विकल्प होगा :

हस्ताक्षर का उपयोग करने के लिए समान है, लेकिन यह सभी DOM म्यूटेशन के बाद समान रूप से फायर करता है।

यह रिएक्ट प्रलेखन में पाया जा सकता है । यदि हम useEffectइसके बजाय उपयोग करते हैं और हम पहले से स्क्रॉल किए गए पृष्ठ को फिर से लोड करते हैं, तो स्क्रॉल गलत होगा और हमारी कक्षा को लागू नहीं किया जाएगा, जिससे अवांछित व्यवहार हो सकता है।

एक उदाहरण:

import React, { useState, useLayoutEffect } from "react"

const Mycomponent = (props) => {
  const [scrolled, setScrolled] = useState(false)

  useLayoutEffect(() => {
    const handleScroll = e => {
      setScrolled(window.scrollY > 0)
    }

    window.addEventListener("scroll", handleScroll)

    return () => {
      window.removeEventListener("scroll", handleScroll)
    }
  }, [])

  ...

  return (
    <div className={scrolled ? "myComponent--scrolled" : ""}>
       ...
    </div>
  )
}

समस्या का एक संभावित समाधान https://codepen.io/dcalderon/pen/mdJzOYq हो सकता है

const Item = (props) => { 
  const [scrollY, setScrollY] = React.useState(0)

  React.useLayoutEffect(() => {
    const handleScroll = e => {
      setScrollY(window.scrollY)
    }

    window.addEventListener("scroll", handleScroll)

    return () => {
      window.removeEventListener("scroll", handleScroll)
    }
  }, [])

  return (
    <div class="item" style={{'--scrollY': `${Math.min(0, scrollY/3 - 60)}px`}}>
      Item
    </div>
  )
}

मैं इसके बारे में उत्सुक हूँ useLayoutEffect। मैं यह देखने की कोशिश कर रहा हूं कि आपने क्या उल्लेख किया है।
जियोनीनिड्स

यदि आपको कोई आपत्ति नहीं है, तो क्या आप कृपया ऐसा होने का एक रेपो + दृश्य उदाहरण प्रदान कर सकते हैं? मैं अभी भी पुन: पेश नहीं कर सका कि आपने useEffectयहां की तुलना में एक मुद्दे के रूप में क्या उल्लेख किया है useLayoutEffect
जियोनीनिड्स

ज़रूर! https://github.com/calderon/uselayout-vs-uselayouteffect । मेरे साथ कल भी ऐसा ही व्यवहार हुआ था। BTW, मैं एक प्रतिक्रिया नौसिखिया हूँ और संभवतः मैं पूरी तरह से गलत हूँ: D: D
Calderón

वास्तव में मैं कई बार यह कोशिश कर रहा हूं, फिर से लोड कर रहा हूं, और कभी-कभी यह नीले रंग के बजाय लाल रंग में दिखाई देता है, जिसका अर्थ है कि यह .Header--scrolledकभी-कभी कक्षा में लागू होता है , लेकिन 100% बार .Header--scrolledLayoutसही ढंग से उपयोग किया जाता है धन्यवाद उपयोग।
कैल्डरॉन


1

यहाँ HOOKS fontAwesomeIcon और Kendo UI React
[] का उपयोग कर एक और उदाहरण दिया गया है ! [यहाँ स्क्रीनशॉट] [1] [1]

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';


const ScrollBackToTop = () => {
  const [show, handleShow] = useState(false);

  useEffect(() => {
    window.addEventListener('scroll', () => {
      if (window.scrollY > 1200) {
        handleShow(true);
      } else handleShow(false);
    });
    return () => {
      window.removeEventListener('scroll');
    };
  }, []);

  const backToTop = () => {
    window.scroll({ top: 0, behavior: 'smooth' });
  };

  return (
    <div>
      {show && (
      <div className="backToTop text-center">
        <button className="backToTop-btn k-button " onClick={() => backToTop()} >
          <div className="d-none d-xl-block mr-1">Top</div>
          <FontAwesomeIcon icon="chevron-up"/>
        </button>
      </div>
      )}
    </div>
  );
};

export default ScrollBackToTop;```


  [1]: https://i.stack.imgur.com/ZquHI.png

यह कमाल का है। मुझे अपने उपयोग में समस्या थी () विंडो.ऑनक्रॉल () का उपयोग करते हुए स्क्रॉल पर अपने नौसैनिक स्टिकी की स्थिति को बदलने में ... इस जवाब के माध्यम से पता चला कि window.addEventListener () और window.removeEventListener () मेरे स्टिकी को नियंत्रित करने के लिए सही दृष्टिकोण हैं एक कार्यात्मक घटक के साथ navbar ... धन्यवाद!
माइकल

1

प्रतिक्रिया हुक के साथ उत्तर के लिए अद्यतन करें

ये दो हुक हैं - एक दिशा के लिए (ऊपर / नीचे / कोई नहीं) और एक वास्तविक स्थिति के लिए

इस तरह का उपयोग करें:

useScrollPosition(position => {
    console.log(position)
  })

useScrollDirection(direction => {
    console.log(direction)
  })

यहाँ हुक हैं:

import { useState, useEffect } from "react"

export const SCROLL_DIRECTION_DOWN = "SCROLL_DIRECTION_DOWN"
export const SCROLL_DIRECTION_UP = "SCROLL_DIRECTION_UP"
export const SCROLL_DIRECTION_NONE = "SCROLL_DIRECTION_NONE"

export const useScrollDirection = callback => {
  const [lastYPosition, setLastYPosition] = useState(window.pageYOffset)
  const [timer, setTimer] = useState(null)

  const handleScroll = () => {
    if (timer !== null) {
      clearTimeout(timer)
    }
    setTimer(
      setTimeout(function () {
        callback(SCROLL_DIRECTION_NONE)
      }, 150)
    )
    if (window.pageYOffset === lastYPosition) return SCROLL_DIRECTION_NONE

    const direction = (() => {
      return lastYPosition < window.pageYOffset
        ? SCROLL_DIRECTION_DOWN
        : SCROLL_DIRECTION_UP
    })()

    callback(direction)
    setLastYPosition(window.pageYOffset)
  }

  useEffect(() => {
    window.addEventListener("scroll", handleScroll)
    return () => window.removeEventListener("scroll", handleScroll)
  })
}

export const useScrollPosition = callback => {
  const handleScroll = () => {
    callback(window.pageYOffset)
  }

  useEffect(() => {
    window.addEventListener("scroll", handleScroll)
    return () => window.removeEventListener("scroll", handleScroll)
  })
}

0

@ ऑस्टिन के उत्तर पर विस्तार करने के लिए, आपको this.handleScroll = this.handleScroll.bind(this)अपने निर्माता से जोड़ना चाहिए :

constructor(props){
    this.handleScroll = this.handleScroll.bind(this)
}
componentDidMount: function() {
    window.addEventListener('scroll', this.handleScroll);
},

componentWillUnmount: function() {
    window.removeEventListener('scroll', this.handleScroll);
},

handleScroll: function(event) {
    let scrollTop = event.srcElement.body.scrollTop,
        itemTranslate = Math.min(0, scrollTop/3 - 60);

    this.setState({
      transform: itemTranslate
    });
},
...

यह देता है handleScroll() ईवेंट श्रोता से कॉल करने पर उचित दायरे तक पहुंच करता है।

इस बात से भी अवगत रहें कि आप .bind(this)इन addEventListenerया removeEventListenerविधियों को नहीं कर सकते क्योंकि वे प्रत्येक को अलग-अलग कार्यों के संदर्भ में लौटाएंगे और घटक के बंद होने पर घटना को हटाया नहीं जाएगा।

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