Làm cách nào để thiết lập Google Analytics cho React-Router?


82

Tôi đang cố gắng thiết lập Google Analytics trên trang web phản ứng của mình và đã gặp một vài gói, nhưng không có gói nào trong số đó có kiểu thiết lập mà tôi có về mặt ví dụ. Tôi hy vọng ai đó có thể làm sáng tỏ điều này.

Gói mà tôi đang xem là, react-ga .

Phương thức kết xuất của tôi trên của tôi index.jstrông như thế này.

React.render((
<Router history={createBrowserHistory()}>
    <Route path="/" component={App}>
        <IndexRoute component={Home} onLeave={closeHeader}/>
        <Route path="/about" component={About} onLeave={closeHeader}/>
        <Route path="/gallery" component={Gallery} onLeave={closeHeader}/>
        <Route path="/contact-us" component={Contact} onLeave={closeHeader}>
            <Route path="/contact-us/:service" component={Contact} onLeave={closeHeader}/>
        </Route>
        <Route path="/privacy-policy" component={PrivacyPolicy} onLeave={closeHeader} />
        <Route path="/feedback" component={Feedback} onLeave={closeHeader} />
    </Route>
    <Route path="*" component={NoMatch} onLeave={closeHeader}/>
</Router>), document.getElementById('root'));

4
Đã đăng câu trả lời cho react-router-4/ react-router-dombên dưới, câu trả lời hàng đầu ở đây là dành cho các phiên bản cũ hơn của react-router và rất tiếc sẽ không hoạt động với v4.
Peter Berg,

Làm cách nào để thêm điều này với StaticRouter khi tôi đang sử dụng SSR phản ứng?
Subhendu Kundu

Câu trả lời:


83

Giữ một tham chiếu đến đối tượng lịch sử của bạn. I E

import { createBrowserHistory } from 'history';

var history = createBrowserHistory();

ReactDOM.render((
    <Router history={history}>
        [...]

Sau đó, thêm một người nghe để ghi lại mỗi lần xem trang. (Điều này giả sử bạn đã thiết lập window.gađối tượng theo cách thông thường.)

history.listen((location) => {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
});

16
Điều này sẽ không tính đến các sự kiện hoặc các loại lần truy cập khác được gửi. Họ sẽ vẫn tham chiếu đến URL tại thời điểm tải trang. Thay vào đó bạn sẽ cần phải thiết lập giá trị mới trên tracker trước khi gửi lần xem trang, ví dụ ga('set', 'page', location.pathname + location.search); ga('send', 'pageview');.
Philip Walton

1
Xin chào David, ví dụ của bạn là sử dụng mã ga thông thường từ trang web ga hay đang sử dụng gói react-ga? Cảm ơn.
John Fu

Vẫn chưa quyết định cách khắc phục, nhưng phần thông tin này cũng có thể hữu ích: stackoverflow.com/questions/30052693/… (nó giải thích tại sao phân bổ có thể không hoạt động chính xác trong một số trường hợp và cũng dẫn đến tỷ lệ thoát cao ).
DeTeam

Bạn không muốn tham số thứ ba trên lệnh gửi. "Mặc dù về mặt kỹ thuật, lệnh gửi cho số lần truy cập trang chấp nhận một trường trang tùy chọn làm tham số thứ ba, việc chuyển trường trang theo cách đó không được khuyến nghị khi theo dõi các ứng dụng trang đơn. Điều này là do các trường được chuyển qua lệnh gửi không được đặt trên trình theo dõi— chúng chỉ áp dụng cho lần truy cập hiện tại. Không cập nhật trình theo dõi sẽ gây ra sự cố nếu ứng dụng của bạn gửi bất kỳ lần truy cập không phải lần xem trang nào (ví dụ: sự kiện hoặc tương tác xã hội), vì những lần truy cập đó sẽ được liên kết với bất kỳ giá trị trang nào mà trình theo dõi có khi nó được tạo. "
Joshua Robinson


29

Cho rằng google analytics được tải và khởi chạy bằng id theo dõi.

Đây là giải pháp cho phiên bản bộ định tuyến phản ứng 4 sử dụng <Route> thành phần để theo dõi lượt xem trang.

<Route path="/" render={({location}) => {
  if (typeof window.ga === 'function') {
    window.ga('set', 'page', location.pathname + location.search);
    window.ga('send', 'pageview');
  }
  return null;
}} />

Bạn chỉ cần hiển thị thành phần này bên trong <Router> (nhưng không phải là con trực tiếp của a <Switch>).

Điều xảy ra là bất cứ khi nào vị trí hỗ trợ thay đổi, nó gây ra kết xuất lại thành phần này (không thực sự hiển thị bất kỳ thứ gì) kích hoạt một lần xem trang.


1
React-router 4. Có gì không?
Anthony Cregan

1
Đã đăng một giải pháp react-router-4 khác bên dưới không liên quan đến việc sửa đổi các tuyến đường riêng lẻ. Đáng buồn thay, đây chắc chắn là một kiểu tình huống "chọn bạn độc".
Peter Berg

1
Điều này không có nghĩa là chuyển đến "/" sẽ không hiển thị gì?
Dana Woodman

3
Chỉ cần có một tuyến đường khác phát ra bất kỳ thứ gì bạn muốn @DanaWoodman. Điều này giả sử tuyến đường không ở trongSwitch
bozdoz

Điều này có theo dõi hai lần xem trang trên trang đích không? Khi GA tự động theo dõi trang đích và chúng tôi kích hoạt một sự kiện xem trang bổ sung cho nó. Hay GA lọc nó ra?
ArneHugo

27

Tôi đang sử dụng Bộ định tuyến React v4 và Thẻ trang web toàn cầu của Google Analytics , này dường như được đề xuất tại thời điểm viết bài này.

Và đây là giải pháp của tôi:

Tạo một thành phần được bọc trong withRouter từ react-router-dom:

import React from 'react';
import { withRouter } from 'react-router-dom';
import { GA_TRACKING_ID } from '../config';

class GoogleAnalytics extends React.Component {
    componentWillUpdate ({ location, history }) {
        const gtag = window.gtag;

        if (location.pathname === this.props.location.pathname) {
            // don't log identical link clicks (nav links likely)
            return;
        }

        if (history.action === 'PUSH' &&
            typeof(gtag) === 'function') {
            gtag('config', GA_TRACKING_ID, {
                'page_title': document.title,
                'page_location': window.location.href,
                'page_path': location.pathname
            });
        }
    }

    render () {
        return null;
    }
}

export default withRouter(GoogleAnalytics);

Chỉ cần thêm thành phần bên trong bộ định tuyến của bạn (tôi tin rằng lý tưởng nhất là sau bất kỳ tuyến nào sẽ được khớp và bất kỳ thành phần Switch nào, bởi vì chức năng phân tích không được ưu tiên hơn so với kết xuất trang web của bạn):

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import IndexPage from './IndexPage';
import NotFoundPage from './NotFoundPage';
import GoogleAnalytics from './GoogleAnalytics';

const App = () => (
    <Router>
        <Switch>
            <Route exact path="/" component={IndexPage} />
            <Route component={NotFoundPage} />
        </Switch>
        <GoogleAnalytics />
    </Router>
);

Như đã nêu:

withRouter sẽ kết xuất lại thành phần của nó mỗi khi tuyến đường thay đổi với các đạo cụ giống như kết xuất đạo cụ

Vì vậy, khi tuyến đường thay đổi, GoogleAnalyticsthành phần sẽ cập nhật, nó sẽ nhận vị trí mới làm đạo cụ và history.actionsẽ PUSHdành cho một mục lịch sử mới hoặc POPđể báo hiệu việc đi ngược lại lịch sử (mà tôi nghĩ không nên kích hoạt lượt xem trang bạn có thể điều chỉnh nếu phát biểu trong componentWillUpdatekhi bạn thấy phù hợp (thậm chí bạn có thể thử componentDidUpdatevới this.propsthay vào đó, nhưng tôi không chắc chắn đó là tốt hơn)).


bozdoz bạn đã thêm Thẻ trang web toàn cầu vào trang của mình như thế nào. Bạn vừa thêm <script async src = " googletagmanager.com/gtag/js?id=GA_TRACKING_ID " ></…> vào trang html của mình bên dưới thẻ body?
me-me

1
@ me-me Vâng. Nhưng trong thẻ body:<body> ... <script ...></script></body>
bozdoz

Một vài chỉnh sửa là cần thiết cho React và React Router mới nhất. Thay đổi componentWillMountthành componentDidMount. Thay đổi page_paththành this.props.location.pathname. Kết hợp các thành phần Switch và GoogleAnalytics trong <div>
mjhm

Không chắc bạn đang nhìn thấy ở đâu componentWillMountvà không chắc chắn sự page_pathkhác biệt như thế nào , nhưng tôi sẽ thử gói thành phần Switch và GA <React.Fragment>thay vì a div. Cảm ơn!
bozdoz

2
Này @JoshuaRobinson, tôi đã viết ở dưới cùng, "... Tôi nghĩ không nên kích hoạt lượt xem trang, nhưng bạn có thể điều chỉnh ...". Câu hỏi này là về việc tích hợp Google Analytics với Bộ định tuyến React, không phải về chế độ xem nào bạn nên ghi lại. Đã nói rằng, tôi có thể điều chỉnh thành phần của mình, vì Google sẽ theo dõi nó theo cách khác nhau. Cảm ơn.
bozdoz

19

Lưu ý nếu bạn đang sử dụng react-router-domgói từ react-router-4bạn có thể xử lý như vậy:

import { Router, Route } from 'react-router-dom';
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
const initGA = (history) => {
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'YOUR_IDENTIFIER_HERE', 'auto');
  ga('send', 'pageview');

  history.listen((location) => {
    console.log("tracking page view: " + location.pathname);
    ga('send', 'pageview', location.pathname);
  });
};

initGA(history);

class App extends Component { //eslint-disable-line
  render() {
    return
      (<Router history={history} >
         <Route exact path="/x" component={x} />
         <Route exact path="/y" component={y} />
       </Router>)
  }
}

Lưu ý rằng điều này yêu cầu bạn cài đặt historygói ( npm install history). Đây đã là một phần phụ thuộc của react-router-dom nên bạn sẽ không thêm bất kỳ trọng lượng trang nào ở đây.

Cũng lưu ý: Không thể sử dụng thành phần BrowserRouter VÀ công cụ theo dõi ga của bạn theo cách này. Điều này không sao vì thành phần BrowserRouter chỉ là một lớp bọc thực sự mỏng xung quanh đối tượng Router. Chúng tôi tạo lại chức năng BrowserRouter ở đây với <Router history={history}>đâu const history = createBrowserHistory();.


bạn chưa bao giờ gọi initGA?
Muhammad Umer

@MuhammadUmer true, vừa sửa nó
Peter Berg

Tại sao bạn không thêm GA vào HTML tĩnh của mình? Tôi đã cộng với bạn. Bởi vì tôi nghĩ lắng nghe đối tượng lịch sử là cách chính xác để đi.
Vince V.

@VinceV. Bạn có thể tưởng tượng khởi tạo historyđối tượng trong bản dựng của mình, sau đó lưu trữ lịch sử trên windowđối tượng và truy cập nó trong thẻ script trong của bạn <head>nhưng tôi nghĩ rằng điều đó cuối cùng sẽ làm cho đường dẫn xây dựng của bạn phức tạp hơn. ¯_ (ツ) _ / ¯
Peter Berg

Nếu bạn đang sử dụng BrowserRouterthành phần, hãy xem câu trả lời bên dưới cung cấp giải pháp thay thế.
Toshe

15

Tôi khuyên bạn nên sử dụng react-router-gagói tuyệt vời cực kỳ nhẹ và dễ cấu hình, đặc biệt là khi sử dụngBrowserRouter trình bao bọc.

Nhập thành phần:

import Analytics from 'react-router-ga';

Sau đó, chỉ cần thêm vào <Analytics>bên trong của bạn BrowserRouter:

<BrowserRouter>
    <Analytics id="UA-ANALYTICS-1">
        <Switch>
            <Route path="/somewhere" component={SomeComponent}/>
        </Switch>
    </Analytics>
</BrowserRouter>

Đây dường như là một giải pháp siêu đơn giản nếu người dùng chỉ quan tâm đến việc theo dõi các lượt xem trang. Rất gầy!
peyo

11

Tôi thích cách Mark Thomas Müller đề xuất ở đây :

Trong index.js của bạn

import ReactGA from 'react-ga'

ReactGA.initialize('YourAnalyticsID')

ReactDOM.render(<App />, document.getElementById('root'))

Các tuyến đường của bạn ở đâu:

import React, { Component } from 'react'
import { Router, Route } from 'react-router-dom'
import createHistory from 'history/createBrowserHistory'
import ReactGA from 'react-ga'

const history = createHistory()
history.listen(location => {
    ReactGA.set({ page: location.pathname })
    ReactGA.pageview(location.pathname)
})

export default class AppRoutes extends Component {
    componentDidMount() {
        ReactGA.pageview(window.location.pathname)
    }

    render() {
        return (
            <Router history={history}>
                <div>
                    <Route path="/your" component={Your} />
                    <Route path="/pages" component={Pages} />
                    <Route path="/here" component={Here} />
                </div>
            </Router>
        )
    }
}

Ngắn gọn, có thể mở rộng và đơn giản :)


tại sao có theo dõi, một toàn cầu, một địa phương?
Thellimist

10

react-router v5.1.0điều này có thể được giải quyết dễ dàng hơn rất nhiều với useLocation.

usePageTracking.js

import { useEffect} from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const usePageTracking = () => {
  const location = useLocation();

  useEffect(() => {
    ReactGA.initialize("UA-000000000-0");
    ReactGA.pageview(location.pathname + location.search);
  }, [location]);
};

export default usePageTracking;

App.js

const App = () => {
  usePageTracking();

  return (...);
};

Xem thêm:

Đây là một phiên bản thông minh hơn một chút:

usePageTracking.js

import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";
import ReactGA from "react-ga";

const usePageTracking = () => {
  const location = useLocation();
  const [initialized, setInitialized] = useState(false);

  useEffect(() => {
    if (!window.location.href.includes("localhost")) {
      ReactGA.initialize("UA-000000000-0");
    }
    setInitialized(true);
  }, []);

  useEffect(() => {
    if (initialized) {
      ReactGA.pageview(location.pathname + location.search);
    }
  }, [initialized, location]);
};

export default usePageTracking;

Tôi không chắc nó cần thiết với 'thẻ gtag' mới nhất. Khi tôi điều hướng, trình gỡ lỗi ga dường như ghi lại chính xác sự kiện đẩy: Processing data layer push: {event: "gtm.historyChange-v2", gtm.historyChangeSource: "pushState", gtm.oldUrlFragment: "", gtm.newUrlFragment: "", gtm.oldHistoryState: null, gtm.newHistoryState: {key: "j5xoc4", state: undefined}, gtm.oldUrl: "https://site/", gtm.newUrl: "https://site/new-url?search-params", gtm.triggers: "1_36"}và một lượt xem trang mới được hiển thị trong bảng điều khiển ga
Dattaya

6

Luôn đi theo cách đề xuất của thư viện

Trong tài liệu React-GA, họ đã thêm một thành phần cộng đồng được khuyến nghị sử dụng với React Router: https://github.com/react-ga/react-ga/wiki/React-Router-v4-withTracker

Thực hiện

import withTracker from './withTracker';

ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <Route component={withTracker(App, { /* additional attributes */ } )} />
    </ConnectedRouter>
  </Provider>,
  document.getElementById('root'),
);

import React, { Component, } from "react";
import GoogleAnalytics from "react-ga";

GoogleAnalytics.initialize("UA-0000000-0");

const withTracker = (WrappedComponent, options = {}) => {
  const trackPage = page => {
    GoogleAnalytics.set({
      page,
      ...options,
    });
    GoogleAnalytics.pageview(page);
  };

  // eslint-disable-next-line
  const HOC = class extends Component {
    componentDidMount() {
      // eslint-disable-next-line
      const page = this.props.location.pathname + this.props.location.search;
      trackPage(page);
    }

    componentDidUpdate(prevProps) {
      const currentPage =
        prevProps.location.pathname + prevProps.location.search;
      const nextPage =
        this.props.location.pathname + this.props.location.search;

      if (currentPage !== nextPage) {
        trackPage(nextPage);
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };

  return HOC;
};

export default withTracker;

1
nếu tôi sử dụng SSR (hiển thị phía máy chủ), GA không biết tiêu đề của trang thực nếu không làm mới trang.
Francis Rodrigues

1
Bạn có thể thay đổi tiêu đề trên mount bằng React
Paras

Cảm ơn vì đăng!
Sailesh Kotha

nơi nào stoređến từ đâu?
user_78361084

Ở đâu ProviderConnectedRouterđến từ đâu? Đây là một câu trả lời không đầy đủ và nên được phản đối
user_78361084

2

Đầu tiên, trong index.js của bạn, hãy đặt hàm onUpdate để gọi ga

import ga from 'ga.js';
onUpdate() {
  console.log('=====GA=====>', location.pathname);
  console.log('=====GA_TRACKING_CODE=====>', GA_TRACKING_CODE);
  ga("send", "pageview", location.pathname);
}

render() {
  return (
    <Router onUpdate={this.onUpdate.bind(this)}>...</Router>
  );
}

Và ga.js:

'use strict';
if(typeof window !== 'undefined' && typeof GA_TRACKING_CODE !== 'undefined') {
  (function(window, document, script, url, r, tag, firstScriptTag) {
    window['GoogleAnalyticsObject']=r;
    window[r] = window[r] || function() {
      (window[r].q = window[r].q || []).push(arguments)
    };
    window[r].l = 1*new Date();
    tag = document.createElement(script),
    firstScriptTag = document.getElementsByTagName(script)[0];
    tag.async = 1;
    tag.src = url;
    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  })(
    window,
    document,
    'script',
    '//www.google-analytics.com/analytics.js',
    'ga'
  );

  var ga = window.ga;

  ga('create', GA_TRACKING_CODE, 'auto');

  module.exports = function() {
    return window.ga.apply(window.ga, arguments);
  };
} else {
  module.exports = function() {console.log(arguments)};
}

phiên bản bộ định tuyến nào được sử dụng ở đây?
Pavan

đó là vì phản ứng Router dom v2 hoặc v3, không v4
Hugo Gresse

2

đây là một cách đơn giản nhất để theo dõi tất cả các đường dẫn với một số cách giải quyết:

npm i --save history react-ga

tạo một tập tin history.js

import { createBrowserHistory } from "history"
import ReactGA from "react-ga"

ReactGA.initialize(process.env.REACT_APP_GA)

const history = createBrowserHistory()
history.listen((location) => {
    ReactGA.pageview(location.pathname)
})

// workaround for initial visit
if (window.performance && (performance.navigation.type === performance.navigation.TYPE_NAVIGATE)) {
    ReactGA.pageview("/")
}

export default history

và sau đó nhập nó vào nơi được đặt Router

import history from "./history"

...

class Route extends Component {
render() {
    return (
        <Router history={history}>
            <Switch>
              <Route path="/" exact component={HomePage} />
              ...
            </Switch>
        </Router>
    )
}

export default Route

Người giới thiệu:

Gustavo Gonzalez | medium.com

Lịch sử | GitHub


2

Tôi khuyên bạn nên sử dụng thư viện phân tích Phân đoạn và làm theo hướng dẫn bắt đầu nhanh React để theo dõi các lệnh gọi trang bằng thư viện bộ định tuyến phản ứng . Bạn có thể cho phép <Route />thành phần xử lý khi trang hiển thị và sử dụng componentDidMountđể gọi pagecác cuộc gọi. Ví dụ dưới đây cho thấy một cách bạn có thể làm điều này:

    const App = () => (
      <div>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/about" component={About} />
        </Switch>
      </div>
    );

    export default App;
    export default class Home extends Component {
      componentDidMount() {
        window.analytics.page('Home');
      }

      render() {
        return (
          <h1>
            Home page.
          </h1>
        );
      }
    }

Tôi là người duy trì https://github.com/segmentio/analytics-react . Với Phân đoạn, bạn sẽ có thể bật và tắt các điểm đến khác nhau bằng cách lật nút nếu bạn muốn thử nhiều công cụ phân tích (chúng tôi hỗ trợ hơn 250 điểm đến) mà không cần phải viết thêm bất kỳ mã nào. 🙂


1

Nếu bạn sử dụng băm hoặc lịch sử trình duyệt, bạn có thể làm:

import trackingHit from 'tracking';

import { Router, browserHistory } from 'react-router';
browserHistory.listen(trackingHit);
// OR
import { Router, hashHistory } from 'react-router';
hashHistory.listen(trackingHit);

ở đâu ./tracking.es6

export default function(location) {
    console.log('New page hit', location.pathname);
    // Do your shizzle here
}

0

triển khai react-ga cơ bản với index.js của bạn

var ReactGA = require('react-ga'); // require the react-ga module
ReactGA.initialize('Your-UA-ID-HERE'); // add your UA code 

function logPageView() { // add this function to your component
  ReactGA.set({ page: window.location.pathname + window.location.search });
  ReactGA.pageview(window.location.pathname + window.location.search);
}

React.render((
<Router history={createBrowserHistory()} onUpdate={logPageView} > // insert onUpdate props here
    <Route path="/" component={App}>
        <IndexRoute component={Home} onLeave={closeHeader}/>
        <Route path="/about" component={About} onLeave={closeHeader}/>
        <Route path="/gallery" component={Gallery} onLeave={closeHeader}/>
        <Route path="/contact-us" component={Contact} onLeave={closeHeader}>
            <Route path="/contact-us/:service" component={Contact} onLeave={closeHeader}/>
        </Route>
        <Route path="/privacy-policy" component={PrivacyPolicy} onLeave={closeHeader} />
        <Route path="/feedback" component={Feedback} onLeave={closeHeader} />
    </Route>
    <Route path="*" component={NoMatch} onLeave={closeHeader} />
</Router>), document.getElementById('root'));

@BigDong Tôi không biết closeHeader là gì. Bạn sẽ phải hỏi OP câu hỏi đó vì mã kết xuất là của anh ấy. Tôi chỉ cho thấy làm thế nào bạn sẽ thực hiện phản ứng-ga cho mã của mình (nhìn cho // ý kiến của tôi)
Isaac Pak

0

Dựa trên đề xuất @ david-l-walsh và @bozdoz

Tôi tạo ra một HOC rằng thực hiện window.ga('set','page','{currentUrl})window.ga('send', 'pageview');chức năng và được easly sử dụng trực tiếp trong trang router ...

đây là HOC:

import React from 'react';
import { history } from '../../store'; // or wherever you createBrowserHistory(); invokation is

function withGAHistoryTrack(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props);
    }

    componentDidMount() {
      const { location } = history;
      const page = location.pathname + location.search;

      if (typeof window.ga === 'function') {
        window.ga('set', 'page', page);
        window.ga('send', 'pageview');
      }
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}

export default withGAHistoryTrack;

và được sử dụng theo cách này trong trang bộ định tuyến:

<Route
 path={'yourPath'}
 component={withGAHistoryTrack(yourComponent)}
 exact
/>

0

Để cập nhật động url trên một số sự kiện (như onClick, v.v.), bạn có thể sử dụng cách sau:

 //Imports
 import ReactGA from "react-ga";
 import { createBrowserHistory } from "history";

 // Add following on some event, like onClick (depends on your requirement)
 const history = createBrowserHistory();
 ReactGA.initialize("<Your-UA-ID-HERE>");
 ReactGA.pageview(history.location.pathname);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.