Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,21 @@ yarn add @every-analytics/react-analytics-provider
You can check examples [here](https://github.com/EveryAnalytics/react-analytics-provider/tree/main/demo)

```tsx
import {AnalyticsProvider} from '@every-analytics/react-analytics-provider';
import {Analytics, AnalyticsProvider} from '@every-analytics/react-analytics-provider';

const analytics: Analytics = {
initialize: () => console.log('onInitialize'),
trackPageView: params => console.log('onTrackPageView', params),
trackEvent: (name, params) => console.log('onTrackEvent', name, params),
trackClick: (name, params) => console.log('onTrackClick', name, params),
set: (...args) => console.log('onSet', args),
setUserId: userId => console.log("onSetUserId", userId),
setUserProperty: params => console.log("onSetUserProperty", params),
}

<AnalyticsProvider
onInitialize={() => console.log('initialized')}
onPageView={(params) => console.log('pageview', params)}
onEvent={(name, params) => console.log('event', name, params)}
onClick={(name, params) => console.log('click', name, params)}
onSetUserId={(userId) => console.log('setUserId', userId)}
analytics={analytics}
>
Comment on lines +45 to 58
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

track이 붙은곳과 아닌곳이 혼재되어있어 헷갈릴거같아요
동사(set)로 시작하는곳엔 track을 생략해주신거같은데
'set을 추적한다' 니까 trackSet이 더 맞지 않을까요?

track- 과 on- 중에 어떤게 더 직관적인지 고민고민..

  • track: 트래킹한다가 명확히 보임
  • on: 이벤트리스너임이 명확히 보임

Copy link
Member Author

@wplong11 wplong11 Sep 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. track이 붙은곳과 아닌곳이 혼재되어있어 헷갈릴거같아요
    동사(set)로 시작하는곳엔 track을 생략해주신거같은데
    'set을 추적한다' 니까 trackSet이 더 맞지 않을까요?

    • track이 붙은 건 이벤트 추적에(기록) 사용되는 것이고, track이 안 붙은 경우는 이벤트 추적에 사용되는 메서드가 아니에요! set은 이벤트 기록이(tracking) 아니라 UserProperty 같은 걸 저장할 때 쓰는 거라고 이해했기 때문에 trackSet이 아니라 set이라고 썼어요

      /** Allows you to set values that persist across all the subsequent gtag() calls on the page.

  2. track- 과 on- 중에 어떤게 더 직관적인지 고민고민..
    track: 트래킹한다가 명확히 보임
    on: 이벤트리스너임이 명확히 보임

    • 저는 Analytics를 호출하는 곳을 고려해서 track을 선택했어요. Analytics를 사용하는 곳에서 이벤트 리스너를 호출한다는 개념보다 Analytics에 이벤트 트래킹해달라고 명령하는 개념으로 보는 것이 자연스럽다고 느껴졌어요. 이벤트 리스너를 호출한 결과로 이벤트가 트래킹된다는 것 보다 의도가 직접적으로 표현되기도 하고요!

<App />
</AnalyticsProvider>
Expand Down
14 changes: 7 additions & 7 deletions demo/with-cra/src/components/NavBar.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
// import { logEvent } from "@every-analytics/react-analytics-provider";
import React from 'react';
import navigate from 'router/navigate';
import {useAnalyticsContext} from '@every-analytics/react-analytics-provider';
import {useAnalytics} from '@every-analytics/react-analytics-provider';

const NavBar = () => {
const analytics = useAnalyticsContext();
const analytics = useAnalytics();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q. Context라는 표현이 불필요해 보여서 지웠습니다. 리액트에서 많이 쓰는 관례인가요? 저는 리액트를 잘 모릅니다 🙏

A. 관례긴 한데 요즘은 생략도 많이 합니다. 우리도 생략해요~ 👍


return (
<header className="App-header">
<NavItem
href="/"
onClick={() => {
analytics.onEvent('Click logo');
analytics.trackEvent('Click logo');
Copy link
Member

@milooy milooy Sep 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아예
analytics.event('click logo')
analytics.click()
analytics.set() // <- 여긴 이미 해주심

으로 짧게가면 어떨까요? ㅎㅎ 굿
기존에 on은 필요 없는게 맞겠어용

Copy link
Member Author

@wplong11 wplong11 Sep 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set에 track이 안 붙은 이유는 아래 스레드에 있어요

track이 붙은 건 이벤트 추적에(기록) 사용되는 것이고, track이 안 붙은 경우는 이벤트 추적에 사용되는 메서드가 아니에요!

#211 (comment)

}}
>
Fruit Store
</NavItem>
<NavItem
href="/products?color=red"
onClick={() => {
analytics.onEvent('Click products', {color: 'red'});
analytics.trackEvent('Click products', {color: 'red'});
}}
>
Red
</NavItem>
<NavItem
href="/products?color=yellow"
onClick={() => {
analytics.onEvent('Click products', {color: 'yellow'});
analytics.trackEvent('Click products', {color: 'yellow'});
}}
>
Yellow
</NavItem>
<NavItem
href="/login"
onClick={() => {
analytics.onClick('Click login', {color: 'yellow'});
analytics.trackClick('Click login', {color: 'yellow'});
}}
>
Login
</NavItem>
<NavItem
href="/set-currency"
onClick={() => {
analytics.onSet({currency: 'KRW'});
analytics.set({currency: 'KRW'});
}}
>
Currency
Expand Down
81 changes: 44 additions & 37 deletions demo/with-cra/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,59 @@ import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import {AnalyticsProvider, googleAnalyticsHelper, amplitudeHelper} from '@every-analytics/react-analytics-provider';
import {
Analytics,
AnalyticsProvider,
googleAnalyticsHelper,
amplitudeHelper,
} from '@every-analytics/react-analytics-provider';
import {fruitLogger} from './utils/fruitLogger';
import {Toaster} from 'react-hot-toast';
import {toaster} from './utils/toaster';

amplitudeHelper.initialize(process.env.REACT_APP_AMPLITUDE_API_KEY);
const persistentValues = {userNo: 123};

const analytics: Analytics = {
initialize: () => {
googleAnalyticsHelper.initialize(process.env.REACT_APP_GA_TRACKING_ID, persistentValues);
},
trackPageView: params => {
// NOTE: Google Analytics(GA4)는 기본적으로 페이지뷰가 적용됩니다 - 따로 추가 필요X
const path = window.location.pathname + window.location.search;
fruitLogger.pageView(path, params);
toaster.pageView(path, params);
amplitudeHelper.logEvent('pageView', {path});
},
trackEvent: (name, params) => {
googleAnalyticsHelper.event(name, params);
fruitLogger.event(name, params);
toaster.event(name, params);
},
trackClick: (name, params) => {
googleAnalyticsHelper.click(name, params);
fruitLogger.click(name, params);
toaster.click(name, params);
},
set: (...args: Parameters<typeof googleAnalyticsHelper.set>) => {
googleAnalyticsHelper.set(...args);
fruitLogger.set(...args);
toaster.set(...args);
},
setUserId: userId => {
// TODO: UserId 설정하는 코드 추가
console.log(userId);
},
setUserProperty: params => {
googleAnalyticsHelper.setUserProperty(params);
fruitLogger.setUserProperty(params);
toaster.setUserProperty(params);
},
};

ReactDOM.render(
<React.StrictMode>
<AnalyticsProvider
onInitialize={() => {
googleAnalyticsHelper.initialize(process.env.REACT_APP_GA_TRACKING_ID, persistentValues);
}}
onPageView={params => {
// NOTE: Google Analytics(GA4)는 기본적으로 페이지뷰가 적용됩니다 - 따로 추가 필요X
const path = window.location.pathname + window.location.search;
fruitLogger.pageView(path, params);
toaster.pageView(path, params);
amplitudeHelper.logEvent('pageView', {path});
}}
onEvent={(name, params) => {
googleAnalyticsHelper.event(name, params);
fruitLogger.event(name, params);
toaster.event(name, params);
}}
onClick={(name, params) => {
googleAnalyticsHelper.click(name, params);
fruitLogger.click(name, params);
toaster.click(name, params);
}}
onSet={(...args: Parameters<typeof googleAnalyticsHelper.set>) => {
googleAnalyticsHelper.set(...args);
fruitLogger.set(...args);
toaster.set(...args);
}}
onSetUserId={userId => {
// TODO: UserId 설정하는 코드 추가
console.log(userId);
}}
onSetUserProperty={params => {
googleAnalyticsHelper.setUserProperty(params);
fruitLogger.setUserProperty(params);
toaster.setUserProperty(params);
}}
>
<AnalyticsProvider analytics={analytics}>
<App />
</AnalyticsProvider>
<Toaster
Expand Down
6 changes: 3 additions & 3 deletions demo/with-cra/src/pages/CurrencyPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {useEffect} from 'react';
import {useAnalyticsContext} from '@every-analytics/react-analytics-provider';
import {useAnalytics} from '@every-analytics/react-analytics-provider';

const CurrencyPage = () => {
const analytics = useAnalyticsContext();
const analytics = useAnalytics();
useEffect(() => {
analytics.onPageView();
analytics.trackPageView();
}, [analytics]);

return <h1>Set Currency KRW</h1>;
Expand Down
6 changes: 3 additions & 3 deletions demo/with-cra/src/pages/ProductsPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import {useEffect} from 'react';
import {getQueryParams} from 'utils/location';
import {useAnalyticsContext} from '@every-analytics/react-analytics-provider';
import {useAnalytics} from '@every-analytics/react-analytics-provider';

const ProductsPage = () => {
const {color} = getQueryParams<{color: string}>();
const products = getProductsByColor(color);
const analytics = useAnalyticsContext();
const analytics = useAnalytics();

useEffect(() => {
analytics.onPageView();
analytics.trackPageView();
}, [analytics]);

return (
Expand Down
8 changes: 4 additions & 4 deletions demo/with-cra/src/pages/UserPropertyPage/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {useEffect, useState} from 'react';
import {useAnalyticsContext} from '@every-analytics/react-analytics-provider';
import {useAnalytics} from '@every-analytics/react-analytics-provider';

const SetUserPropertyPage = () => {
const analytics = useAnalyticsContext();
const analytics = useAnalytics();
useEffect(() => {
analytics.onPageView();
analytics.trackPageView();
}, [analytics]);

const [favoriteFood, setFavoriteFood] = useState('한식');
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
analytics.onSetUserProperty({favoriteFood});
analytics.setUserProperty({favoriteFood});
};

return (
Expand Down
50 changes: 30 additions & 20 deletions demo/with-nextjs/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import {AnalyticsProvider} from '@every-analytics/react-analytics-provider';
import {Analytics, AnalyticsProvider} from '@every-analytics/react-analytics-provider';
import {AppProps} from 'next/app';
import {Layout} from '../layout/Layout';

function DemoApp({Component, pageProps}: AppProps) {
const analytics: Analytics = {
initialize: () => {
console.log('onInitialize');
},
trackPageView: params => {
// NOTE: Google Analytics(GA4)는 기본적으로 페이지뷰가 적용됩니다 - 따로 추가 필요X
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onTrackPageView', params);
},
trackEvent: (name, params) => {
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onTrackEvent', name, params);
},
trackClick: (name, params) => {
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onTrackClick', name, params);
},
set: (...args) => {
console.log('onSet', args);
},
setUserId: userId => {
console.log('onSetUserId', userId);
},
setUserProperty: params => {
console.log('onSetUserProperty', params);
},
};

return (
<AnalyticsProvider
onInitialize={() => {
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onInitialize');
}}
onPageView={params => {
// NOTE: Google Analytics(GA4)는 기본적으로 페이지뷰가 적용됩니다 - 따로 추가 필요X
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onPageView', params);
}}
onEvent={(name, params) => {
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onEvent', name, params);
}}
onClick={(name, params) => {
// TODO: 이준희 => ga, amplitude event tracking 코드 추가
console.log('onClick', name, params);
}}
>
<AnalyticsProvider analytics={analytics}>
<Layout>
<Component {...pageProps} />
</Layout>
Expand Down
8 changes: 4 additions & 4 deletions src/components/AnalyticsClick/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, {useCallback} from 'react';
import {useAnalyticsContext} from '../../contexts';
import {useAnalytics} from '../../contexts';
import {UnknownRecord} from '../../types/common';

export interface AnalyticsClickProps {
Expand All @@ -9,13 +9,13 @@ export interface AnalyticsClickProps {
}

export const AnalyticsClick = ({children, name, params}: AnalyticsClickProps) => {
const {onClick} = useAnalyticsContext();
const {trackClick} = useAnalytics();

const child = React.Children.only(children) as React.ReactElement;

const handleChildClick = useCallback(() => {
onClick(name, {action_type: 'click', ...params});
}, [name, params, onClick]);
trackClick(name, {action_type: 'click', ...params});
}, [name, params, trackClick]);

return React.cloneElement(child, {
onClick: handleChildClick,
Expand Down
6 changes: 3 additions & 3 deletions src/components/AnalyticsPageView/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import {useAnalyticsContext} from '../../contexts/useAnalyticsContext';
import {useAnalytics} from '../../contexts/useAnalytics';
import {UnknownRecord} from '../../types/common';

export interface AnalyticsPageViewProps {
Expand All @@ -8,10 +8,10 @@ export interface AnalyticsPageViewProps {
}

export const AnalyticsPageView = ({children, params}: AnalyticsPageViewProps) => {
const analytics = useAnalyticsContext();
const analytics = useAnalytics();

React.useEffect(() => {
analytics.onPageView(params);
analytics.trackPageView(params);
}, [analytics, params]);

return <>{children}</>;
Expand Down
42 changes: 7 additions & 35 deletions src/components/AnalyticsProvider/index.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,20 @@
import * as React from 'react';

import AnalyticsProviderContext from '../../contexts/AnalyticsProviderContext';
import {UnknownRecord} from '../../types/common';
import {Analytics} from '../../core';

interface Props {
onInitialize(): void;
onPageView?(params?: UnknownRecord): void;
onEvent?(name: string, params?: UnknownRecord): void;
onClick?(name: string, params?: UnknownRecord): void;
onSet?(...args: [string, UnknownRecord] | [UnknownRecord]): void;
onSetUserId?(userId: string | null): void;
onSetUserProperty?(params: UnknownRecord): void;
analytics: Analytics;
children: React.ReactNode;
}

export function AnalyticsProvider({
onInitialize,
onPageView = () => null,
onEvent = () => null,
onClick = () => null,
onSet = () => null,
onSetUserId = () => null,
onSetUserProperty = () => null,
children,
}: Props) {
export function AnalyticsProvider({analytics, children}: Props) {
React.useEffect(() => {
onInitialize();
}, [onInitialize]);
analytics.initialize();
}, [analytics]);

return React.useMemo(
() => (
<AnalyticsProviderContext.Provider
value={{
onPageView,
onEvent,
onClick,
onSet,
onSetUserId,
onSetUserProperty,
}}
>
{children}
</AnalyticsProviderContext.Provider>
),
[children, onClick, onEvent, onPageView, onSet, onSetUserId, onSetUserProperty],
() => <AnalyticsProviderContext.Provider value={analytics}>{children}</AnalyticsProviderContext.Provider>,
[children, analytics],
);
}
Loading