-
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
Chapter 2 / 순수함수 렌더링 #6
Changes from 9 commits
87bd45e
9cf9c2a
60386c5
6fc02b7
13a8f25
647a50b
8ca4019
40fe8ff
4af4356
f8ad027
5b0e4f2
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,16 @@ | ||
const getNotCompleteCount = (todos) => todos.filter((todo) => !todo.completed).length; | ||
const getNotCompleteTextContent = (todos) => { | ||
const count = getNotCompleteCount(todos); | ||
if (count === 0) return 'No item left'; | ||
if (count === 1) return '1 Item left'; | ||
return `${count} Items left`; | ||
}; | ||
|
||
export default (targetElement, state) => { | ||
const { todos } = state; | ||
|
||
const newElement = targetElement.cloneNode(true); | ||
newElement.textContent = getNotCompleteTextContent(todos); | ||
|
||
return newElement; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
const getAllListAnchorsFrom = (element) => [...element.querySelectorAll('li a')]; | ||
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. 책에서는 spread 구문은 iterable 객체만 배열로 바꿀 수 있고 |
||
const setSelectedClassNameToAnchors = (anchors, currentFilter) => { | ||
anchors.forEach((anchor) => { | ||
if (anchor.textContent === currentFilter) { | ||
anchor.classList.add('selected'); | ||
} else { | ||
anchor.classList.remove('selected'); | ||
} | ||
}); | ||
}; | ||
|
||
export default (targetElement, state) => { | ||
const { currentFilter } = state; | ||
|
||
const newElement = targetElement.cloneNode(true); | ||
const anchors = getAllListAnchorsFrom(newElement); | ||
setSelectedClassNameToAnchors(anchors, currentFilter); | ||
|
||
return newElement; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { createInnerHTML } from './utils.js'; | ||
|
||
const getTodoItemElement = ({ text, completed }) => { | ||
const toggle = createInnerHTML('input', { | ||
attributes: { | ||
class: 'toggle', | ||
type: 'checkbox', | ||
checked: completed, | ||
}, | ||
}); | ||
const label = createInnerHTML('label', { | ||
innerHTML: text, | ||
}); | ||
const edit = createInnerHTML('input', { | ||
attributes: { | ||
class: 'edit', | ||
value: text, | ||
}, | ||
}); | ||
const viewBox = createInnerHTML('div', { | ||
attributes: { | ||
class: 'view', | ||
}, | ||
innerHTML: toggle + label, | ||
}); | ||
|
||
return createInnerHTML('li', { | ||
attributes: { | ||
class: completed ? 'completed' : '', | ||
}, | ||
innerHTML: `${viewBox}${edit}`, | ||
}); | ||
}; | ||
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. 가독성 측면에서는 템플릿 스트링 사용하는게 더 좋아보이는데 어떻게 생각하시나요? |
||
|
||
export default (targetElement, state) => { | ||
const { todos } = state; | ||
|
||
const innerHTML = todos.map((todo) => getTodoItemElement(todo)).join(''); | ||
|
||
const newElement = targetElement.cloneNode(true); | ||
newElement.innerHTML = innerHTML; | ||
|
||
return newElement; | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,13 @@ | ||||||
export const createInnerHTML = (tagName, { attributes = {}, innerHTML = '' } = {}) => { | ||||||
const arrtibuteString = Object.entries(attributes) | ||||||
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. 혹시 |
||||||
.map(([name, value]) => { | ||||||
if (typeof value === 'boolean') return value ? name : ''; | ||||||
return `${name}="${value}"`; | ||||||
}) | ||||||
.join(' '); | ||||||
const closeTagString = innerHTML !== '' ? `${innerHTML}</${tagName}>` : ''; | ||||||
|
||||||
return `<${tagName} ${arrtibuteString}>${closeTagString}`; | ||||||
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.
Suggested change
|
||||||
}; | ||||||
|
||||||
export default {}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { createInnerHTML } from './utils'; | ||
|
||
describe('유틸리티 함수 테스트', () => { | ||
let container; | ||
|
||
beforeEach(() => { | ||
container = document.createElement('div'); | ||
}); | ||
|
||
test('createInnerHTML: 빈 태그를 잘 생성하는가?', () => { | ||
const tagNames = ['div', 'input', 'span', 'a', 'ul', 'li']; | ||
|
||
tagNames.forEach((tagName) => { | ||
container.innerHTML = createInnerHTML(tagName); | ||
const testTarget = container.querySelector(tagName); | ||
|
||
expect(testTarget.tagName).toBe(tagName.toUpperCase()); | ||
expect(testTarget.innerHTML).toBe(''); | ||
}); | ||
}); | ||
|
||
test('createInnerHTML: 속성을 잘 할당하는가?', () => { | ||
container.innerHTML = createInnerHTML('input', { | ||
attributes: { | ||
class: 'test-input', | ||
type: 'checkbox', | ||
checked: true, | ||
}, | ||
}); | ||
const testTarget = container.querySelector('input'); | ||
|
||
expect(testTarget.className).toBe('test-input'); | ||
expect(testTarget.type).toBe('checkbox'); | ||
expect(testTarget.checked).toBe(true); | ||
}); | ||
|
||
test('createInnerHTML: innerHTML을 잘 할당하는가?', () => { | ||
const html = [ | ||
createInnerHTML('div', { | ||
attributes: { | ||
class: 'inner-div', | ||
}, | ||
innerHTML: 'hello', | ||
}), | ||
createInnerHTML('input', { | ||
attributes: { | ||
class: 'inner-input', | ||
type: 'number', | ||
value: '1', | ||
}, | ||
}), | ||
].join(''); | ||
|
||
container.innerHTML = createInnerHTML('div', { | ||
attributes: { | ||
class: 'test-container', | ||
}, | ||
innerHTML: html, | ||
}); | ||
const testTarget = container.querySelector('.test-container'); | ||
const innerDiv = testTarget.querySelector('.inner-div'); | ||
const innerInput = testTarget.querySelector('.inner-input'); | ||
|
||
expect(innerDiv.textContent).toBe('hello'); | ||
expect(innerInput.value).toBe('1'); | ||
}); | ||
}); |
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.
함수는 모조리 분리하시네요 역시 대상혁