-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Life cycle hook 개발 #3
Changes from 9 commits
c30b5d5
ef85dc5
6f91c79
4dfc981
8a06b0e
5e2bdca
b3694e9
bd5b7e3
5ce19fe
9db0d16
c5d22f9
3dae954
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Default from './index'; | ||
|
||
describe('useDidMount index', () => { | ||
it('default export이여야 한다', () => { | ||
expect(Default).toBeDefined(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './useDidMount'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { useState } from 'react'; | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
|
||
import useDidMount from './useDidMount'; | ||
|
||
describe('useDidMount', () => { | ||
it('default export이여야 한다', () => { | ||
expect(useDidMount).toBeDefined(); | ||
}); | ||
|
||
it('effectCallback이 실행되어야 한다', () => { | ||
const effectCallback = jest.fn(); | ||
renderHook(() => useDidMount(effectCallback)); | ||
expect(effectCallback).toBeCalled(); | ||
}); | ||
|
||
it('rerender 시 1번 실행되어야 한다', () => { | ||
const effectCallback = jest.fn(); | ||
const { rerender } = renderHook(() => useDidMount(effectCallback)); | ||
rerender(); | ||
expect(effectCallback).toBeCalledTimes(1); | ||
}); | ||
|
||
describe('useDidMount Component', () => { | ||
const STATE_CHANGE_BUTTON_TEXT = 'change'; | ||
const mockCallback = jest.fn(); | ||
|
||
const App = () => { | ||
const [_, setState] = useState(false); | ||
|
||
useDidMount(mockCallback); | ||
return ( | ||
<div> | ||
<button type="button" onClick={() => setState((prev) => !prev)}> | ||
{STATE_CHANGE_BUTTON_TEXT} | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('mockCallback이 실행되어야 한다', () => { | ||
render(<App />); | ||
expect(mockCallback).toBeCalledTimes(1); | ||
}); | ||
|
||
it('mockCallback은 상태가 변해도 1번 실행되어야 한다', () => { | ||
render(<App />); | ||
expect(mockCallback).toBeCalledTimes(1); | ||
const setStateButton = screen.getByText(STATE_CHANGE_BUTTON_TEXT); | ||
fireEvent.click(setStateButton); | ||
expect(mockCallback).toBeCalledTimes(1); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { EffectCallback, useEffect, useRef } from 'react'; | ||
|
||
const useDidMount = (effectCallback: EffectCallback) => { | ||
const didMountRef = useRef<boolean>(false); | ||
|
||
useEffect(() => { | ||
if (didMountRef.current) return; | ||
didMountRef.current = true; | ||
effectCallback(); | ||
}, []); | ||
}; | ||
|
||
export default useDidMount; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Default from './index'; | ||
|
||
describe('useDidUpdate index', () => { | ||
it('default export이어야 한다', () => { | ||
expect(Default).toBeDefined(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './useDidUpdate'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { useState } from 'react'; | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
|
||
import useDidUpdate from './useDidUpdate'; | ||
|
||
describe('useDidUpdate', () => { | ||
it('default export이여야 한다', () => { | ||
expect(useDidUpdate).toBeDefined(); | ||
}); | ||
|
||
it('첫 호출시 effectCallback이 실행되면 안된다', () => { | ||
const mockCallback = jest.fn(); | ||
renderHook(() => useDidUpdate(mockCallback, [])); | ||
expect(mockCallback).not.toBeCalled(); | ||
}); | ||
|
||
describe('useDidUpdate Component', () => { | ||
const STATE_CHANGE_BUTTON_TEXT = 'change'; | ||
const mockCallback = jest.fn(); | ||
|
||
const App = () => { | ||
const [state, setState] = useState<number>(0); | ||
|
||
useDidUpdate(mockCallback, [state]); | ||
|
||
return ( | ||
<div> | ||
<button type="button" onClick={() => setState((prev) => prev + 1)}> | ||
{STATE_CHANGE_BUTTON_TEXT} | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('마운트 시 effectCallback이 실행되면 안된다', () => { | ||
render(<App />); | ||
expect(mockCallback).not.toBeCalled(); | ||
}); | ||
|
||
it('dependency list 업데이트 시 effectCallback이 실행되어야 한다', () => { | ||
render(<App />); | ||
const setStateButton = screen.getByText(STATE_CHANGE_BUTTON_TEXT); | ||
fireEvent.click(setStateButton); | ||
expect(mockCallback).toBeCalledTimes(1); | ||
fireEvent.click(setStateButton); | ||
expect(mockCallback).toBeCalledTimes(2); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { DependencyList, EffectCallback, useEffect, useRef } from 'react'; | ||
|
||
const useDidUpdate = (effectCallback: EffectCallback, dependencyList: DependencyList) => { | ||
const didMountRef = useRef<boolean>(false); | ||
|
||
useEffect(() => { | ||
if (!didMountRef.current) { | ||
didMountRef.current = true; | ||
return; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오오 이건 설마.. react18 대응인가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 18을 따로 대응할 생각은 없었어요 ㅋㅋㅋㅋ
단순히 mount 시에는 실행되지 않게 하고, 디펜던시가 업데이트된 후에 실행되도록 작성하기 위한 부분이에요
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 맞아요. effect 두번 호출되는거.. ㅠ |
||
|
||
effectCallback(); | ||
}, [...dependencyList]); | ||
}; | ||
|
||
export default useDidUpdate; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import Default from './index'; | ||
|
||
describe('useWillUnmount index', () => { | ||
it('default export이어야 한다', () => { | ||
expect(Default).toBeDefined(); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './useWillUnmount'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { useState } from 'react'; | ||
import { cleanup, fireEvent, render, screen } from '@testing-library/react'; | ||
import { renderHook } from '@testing-library/react-hooks'; | ||
|
||
import useWillUnmount from './useWillUnmount'; | ||
|
||
describe('useWillUnmount', () => { | ||
it('default export이어야 한다', () => { | ||
expect(useWillUnmount).toBeDefined(); | ||
}); | ||
|
||
it('첫 호출시 callback이 실행되면 안된다', () => { | ||
const mockCallback = jest.fn(); | ||
renderHook(() => useWillUnmount(mockCallback)); | ||
expect(mockCallback).not.toBeCalled(); | ||
}); | ||
|
||
describe('useWillUnmount Component', () => { | ||
const TOGGLE_BUTTON_TEXT = 'toggle'; | ||
const mockCallback = jest.fn(); | ||
|
||
const Child = () => { | ||
useWillUnmount(mockCallback); | ||
|
||
return <div />; | ||
}; | ||
|
||
const App = () => { | ||
const [state, setState] = useState<boolean>(true); | ||
|
||
return ( | ||
<div> | ||
<button type="button" onClick={() => setState((prev) => !prev)}> | ||
{TOGGLE_BUTTON_TEXT} | ||
</button> | ||
|
||
{state && <Child />} | ||
</div> | ||
); | ||
}; | ||
|
||
afterEach(() => { | ||
cleanup(); | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
it('마운트 시 callback이 실행되면 안된다', () => { | ||
render(<App />); | ||
expect(mockCallback).not.toBeCalled(); | ||
}); | ||
|
||
it('Child가 unmount시 callback이 실행된다', () => { | ||
render(<App />); | ||
const toggleButton = screen.getByText(TOGGLE_BUTTON_TEXT); | ||
fireEvent.click(toggleButton); // false | ||
expect(mockCallback).toBeCalledTimes(1); | ||
|
||
fireEvent.click(toggleButton); // true | ||
fireEvent.click(toggleButton); // false | ||
expect(mockCallback).toBeCalledTimes(2); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { useEffect } from 'react'; | ||
|
||
const useWillUnmount = (callback: VoidFunction) => { | ||
useEffect(() => { | ||
return callback; | ||
}, []); | ||
}; | ||
|
||
export default useWillUnmount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
뭔가.. 간단하게 만들 수 있을 것 같은뎅..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 위에 똑같은 테스트코드가 있었네요 ㅋㅋ