κ°μ
Declarative React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
Reactμμλ Reactλ₯Ό μ μΈμ μ΄λΌκ³ μ μ€λͺ νκ³ μμ΅λλ€. “μ μΈν λ·°λ μ½λλ₯Ό μμΈ‘ κ°λ₯νκ³ , λλ²κΉ μ μ½κ² λ§λ λ€” λΌκ³ μ€λͺ νκ³ μμΌλ©°, Reactκ° μ μΈν νλ‘κ·Έλλ°μ ν¨λ¬λ€μμ μ§ν₯νλ μ΄μ μ νΉμ§μ λν΄μ μμ보μμ΅λλ€.
λͺ λ Ήν νλ‘κ·Έλλ°
μ μΈν νλ‘κ·Έλλ°μ μκΈ° μν΄ κΈ°μ‘΄ λͺ λ Ήν νλ‘κ·Έλλ°μ νΉμ§μ κ°λ΅νκ² μμλ³΄κ² μ΅λλ€. λͺ λ Ήν νλ‘κ·Έλλ°(Imperative Programming)μ λͺ λ Ήμ΄λ₯Ό λͺ μμ μΌλ‘ μ§μ νμ¬ νλ‘κ·Έλ¨ λμ μνλ₯Ό λ³κ²½ μν€λ νλ‘κ·Έλλ° λ°©μ μ λλ€. νλ‘κ·Έλ¨μ λμμ νλ¦μ μ€μ μ λλ νΉμ§μ΄ μμ΅λλ€.
//DOMμ λ
ΈμΆμν¬ λ¦¬μ€νΈ λ³μλ₯Ό μμ±νλ€.
const list = ['foo', 'bar'];
//νμ li μμλ₯Ό μΆκ°μν€κΈ° μν ul μμλ₯Ό μμ±νλ€.
const $ul = document.createElement('ul');
//listμ κΈΈμ΄ λ§νΌ μννλ©° listItem μμλ₯Ό μμ±
for (let index = 0; index < list.length; index++) {
const item = document.createTextNode(list[index]);
const $listItem = document.createElement('li');
$listItem.appendChild(item);
$ul.appendChild($listItem);
}
//html bodyμ λ λλ§
document.body.appendChild($ul);
μμ μμ μ½λλ λͺ λ Ήν λ°©μμ 리μ€νΈλ₯Ό λ λλ§ν΄μ£Όλ μ½λ μ λλ€. λͺ λ Ήν μ½λμ νΉμ§μ λ€μκ³Ό κ°μ΅λλ€.
- λ³λμ λͺ¨λ λΆλ¦¬ μμ΄ μ°μμ μΈ κ³μ° κ³Όμ μΌλ‘ μ΄λ£¨μ΄μ Έ μμ΄ μ€ν μλκ° λΉ λ¦ λλ€.
- μΈλΆμ μΈ λμ μ¬νμ΄ λͺ λ Ήλ¬Έμ μ°μμΌλ‘ ꡬμ±λμ΄ μκΈ° λλ¬Έμ, 볡μ‘λκ° μ¦κ°ν μλ‘ μ΄ν΄νλ λ° μκ°κ³Ό λΉμ©μ΄ μλμ μΌλ‘ λ λ§μ΄ λ€ μ μμ΅λλ€.
- κΈ°λ₯μ λ³κ²½ν λ λ³μ κ° ν λΉ/μμ μ΄ λΆκ°νΌνκ² νμνκΈ° λλ¬Έμ, μ€ν νλ¦κ³Ό λΆμ ν¨κ³Ό(Side Effect)μ μν₯μ λ―ΈμΉ μ μμ΅λλ€.
μμ½νμλ©΄, κ°λ¨νκ³ λ¨μ κ³μ° μ ν리μΌμ΄μ μλ λΉ λ₯Έ μ€νκ³Ό κ°λ μ±μΌλ‘ μΈν μ₯μ μ΄ μμ§λ§, 볡μ‘ν μ ν리μΌμ΄μ μΌ μλ‘ κ΄λ¦¬κ° μ΄λ ΅λ€λ νΉμ§μ΄ μμ΅λλ€.
μ μΈν νλ‘κ·Έλλ°
μ΄μ μ μΈν νλ‘κ·Έλλ°μ νΉμ§μ λ§μλ리λλ‘ νκ² μ΅λλ€. μ μΈν νλ‘κ·Έλλ°μ μΆμν κ³μΈ΅κ³Ό μ μ΄ νλ¦μ λͺ
μμ μΌλ‘ μ§μ νμ§ μκ³ , νλ‘κ·Έλ¨μ΄ μννλ μμ
μ μ€λͺ
νλ λ° μ€μ μ λ ν¨λ¬λ€μ μ
λλ€. JavaScript
μμλ λͺ
λ Ήν νλ‘κ·Έλλ°μΌλ‘ μμ±λ μ½λλ₯Ό μΆμνλ₯Ό ν΅ν΄ μ μΈν μ½λλ‘ λ³νν μ μμ΅λλ€. (λ€μ€ ν¨λ¬λ€μ μΈμ΄)
μΆμνλ₯Ό ν΅ν μ μΈν νλ‘κ·Έλλ°
//DOMμ λ
ΈμΆμν¬ λ¦¬μ€νΈ λ³μλ₯Ό μμ±νλ€.
const list = ['foo', 'bar'];
//μμλ₯Ό μμ±νλ€.
const createElement = (element) => {
return document.createElement(element);
};
//listμ κΈΈμ΄ λ§νΌ μννλ©° listItem μμλ₯Ό μμ±
const createListItem = (list) => {
const $ul = createElement('ul');
list.forEach((item) => {
const $item = createElement('li');
$item.appendChild(document.createTextNode(item));
$ul.appendChild($item);
});
return $ul;
};
//λ λλ§νλ€.
const render = (element, attachElement) => {
return attachElement.appendChild(element);
};
render(createListItem(list), document.body);
μμ μμ±νλ μ½λλ₯Ό μ μΈν μ½λλ‘ μ¬κ΅¬μ±ν΄λ³΄μμ΅λλ€. λ³λμ ν¨μλ‘ λΆλ¦¬νμ¬ μΆμνλ₯Ό νμμΌλ©°, μ΄λ 곧 μ¬μ¬μ©μ±μ΄ μ¦κ°νλ€λ νΉμ§μ κ°κ² λμμ΅λλ€. μ μΈν νλ‘κ·Έλλ°μ νΉμ§μ μΆμν λ λ²¨μ΄ λμμλ‘, μ¬μ©νλ μ μ₯μμλ λ΄λΆλ₯Ό μ κ²½μ°μ§ μμλ λ©λλ€.
λμ λ 벨μ μΆμν
//render
const render = (initialState, createElement) => {
const renderToApp = (element) => {
const $app = document.getElementById("app");
$app.innerHTML = element;
};
//setStateν¨μλ₯Ό νΈμΆνλ μκ° renderToApp νΈμΆ
const setState = (state) => {
renderToApp(createElement(state, setState));
};
setState(initialState);
};
//render νΈμΆ
render({ list: ["foo", "bar"] }, (state, setState) => {
setState({ list: [...state.list, "jiny"] });
return `<ul>
${state.list.map((item) => {
return `<li>${item}</li>`;
})}
</ul>`;
});
});
- μΆμν λ λ²¨μ΄ λμμλ‘, νΈμΆνλ λΆλΆμμ ꡬ체μ μΈ λμμ λν μ 보λ₯Ό μ νμκ° μμ΄μ§λλ€. (κ°λ μ±κ³Ό μ΄ν΄λ ν₯μ)
- μΆμνλ ν¨μλ₯Ό μ¬μ¬μ©ν¨μΌλ‘μ¨ μ μΈμ μΈ μ½λλ₯Ό μ¬μ©ν μ μμ΅λλ€.
- ν¨μ νΈμΆ λ°©μμΌλ‘ μΈν΄ λ©λͺ¨λ¦¬ ν λΉλμ΄ μ¦κ°νλ λ¨μ μ μμ΅λλ€.
Reactμ μ μΈν νλ‘κ·Έλλ°
μ΄μ μ λͺ λ Ήνκ³Ό μ μΈν ν¨λ¬λ€μμ μ΄ν΄νκ³ , Reactμμ μ€λͺ νκ³ μλ μ μΈνμ μ₯μ μ μ΄ν΄λ³΄κ² μ΅λλ€. Reactμμλ μ¬μ©μκ° UIλ₯Ό μν©μ λ°λΌ μ΄λ»κ² ννν μ§ μ μΈλ§ νλ©΄ λλ©°, μ μΈμ μΈ μ½λλ‘ μμ±λμ΄ μμ΄ UI μ λ°μ΄νΈλ React λ΄λΆμμ μ²λ¦¬λ©λλ€. λ§μ½μ μ΄ λ°©μμ λͺ λ Ήν νλ‘κ·Έλλ°μΌλ‘ μμ±νλ€λ©΄ μ΄λ»κ² λ κΉμ?
/** κ°λ¨ν ν
μ€νΈ νΌμ μ μΆνλ UI */
const loadingMessage = 'λ‘λ©μ€μ
λλ€..';
const successMessage = 'μ μΆμ μ±κ³΅νμμ΅λλ€.';
const $form = document.getElementById('form');
const $textarea = document.getElementById('textarea');
let $status = document.getElementById('status');
//display μν κ΄λ¦¬
const setHideElement = (element, state) => {
element.style.display = state ? 'none' : '';
};
//text μν κ΄λ¦¬
const setStatusElementText = (element, state) => {
element.textContent = state;
};
//network μν©μ κ°μ ν form μ μΆ
const fetchForm = (formText) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (formText.length) {
resolve();
return;
}
reject(new Error('Form text is empty'));
}, 2000);
});
};
//submit event
const handleSubmit = async (e) => {
e.preventDefault();
setHideElement($status, false);
try {
await fetchForm($textarea.value);
setStatusElementText($status, `${successMessage} λ΄μ©: ${$textarea.value}`);
} catch (error) {
setStatusElementText($status, error.message);
}
};
$form.onsubmit = handleSubmit;
μ΄λ κ² UI μνλ₯Ό νννλ κ²λ μ΄λ―Έ μ½λκ° λ³΅μ‘νλ°, λ 볡μ‘ν UIμΌμλ‘ μν λ³ ννν΄μΌνλ κ΄λ¦¬ μμ€λ λμ± λ³΅μ‘ν΄μ§κ²λ©λλ€. μ΄λ₯Ό ν΄κ²°νκΈ° μν΄, Reactμμλ μ¬λ¬ κ²½μ°μ νλμ μνλ‘ λλ©΄μ λ°μ΄ν° νλ¦μ λ¨λ°©ν₯ μ»΄ν¬λνΈλ‘ νλ₯΄κ² νμμ΅λλ€. μ΄λ¬ν ν¨ν΄μ Single Source of TruthλΌκ³ ν©λλ€.
- κ°κ°μ UIλ³ μνλ₯Ό λͺ λ Ήν μ½λλ‘ κ΅¬μ±νμ λ μν κ΄κ³μ μ°Έμ‘°νλ DOM Tree ꡬ쑰λ 볡μ‘ν΄μ Έ κ΄λ¦¬νκΈ° μ΄λ €μμ§λλ€.
- μλ‘μ΄ UI μμλ μνΈμμ©μ μν μ΄λ²€νΈλ₯Ό μμ νκ±°λ μΆκ°νλ €λ©΄ κΈ°μ‘΄ μνΈμμ©μ΄ μ μ΄λ£¨μ΄μ Έμλμ§ μΈλ°ν λλ²κΉ μ΄ νμλ‘νκ²λ©λλ€.
Reactκ° μ μν μ μΈμ UI μ μ΄
propμ νμ©ν μκ° μν μλ³
μ»΄ν¬λνΈλ₯Ό μ¬μ©νλ©΄ props
μ ν΅ν΄ λ€μν UI μνλ₯Ό μλ³ν μ μμ΅λλ€. Reactμμλ μ΄λ―Έ λμ μΆμν μμ€μ λ¬μ±νκΈ° λλ¬Έμ, μ¬μ©μλ JSX λ¬Έλ²μ ν΅ν΄ UI μνλ₯Ό μ μ΄νκΈ° μν μμ± κ°κ³Ό μνλ³λ‘ μ΄λ»κ² ννν μ§ μμ±νκΈ°λ§ νλ©΄ λ©λλ€.
export default Form = ({ status = 'empty' }) => {
if (status === 'success') {
return <h1>μ΄λ―Έ νΌμ μ μΆνμμ΅λλ€.</h1>;
}
return (
<>
<h2>Form</h2>
<form>
<textarea disabled={status === 'submitting'} />
<br />
<button disabled={status === 'empty' || status === 'submitting'}>Submit</button>
{status === 'error' && <p className="Error">μλ¬κ° λ°μνμμ΅λλ€.</p>}
</form>
</>
);
};
μμ μ»΄ν¬λνΈ μ½λλ λ΄λΆμ μΌλ‘ μλμ κ°μ΄ λ³νμ΄ λ©λλ€.
const Form = ({ status = 'empty' }) => {
if (status === 'success') {
return React.createElement('h1', null, 'μ΄λ―Έ νΌμ μ μΆνμμ΅λλ€.');
}
return React.createElement(
React.Fragment,
null,
React.createElement('h2', null, 'Form'),
React.createElement(
'form',
null,
React.createElement('textarea', { disabled: status === 'submitting' }),
React.createElement('br'),
React.createElement('button', { disabled: status === 'empty' || status === 'submitting' }, 'Submit'),
status === 'error' && React.createElement('p', { className: 'Error' }, 'μλ¬κ° λ°μνμμ΅λλ€.')
)
);
};
export default Form;
μ μΈμ μΈ hookμ ν΅ν μν μ μ΄
Reactμμλ hook
μ ν΅ν΄μ μ»΄ν¬λνΈ κ° μνλ€μ 곡μ νκ³ , μν μ μ΄λ₯Ό ν μ μμ΅λλ€. μ΄ λΆλΆμ΄ μ΄λ»κ² μ μΈνμΌλ‘ μ΄λ£¨μ΄μ Έμλμ§ μ΄ν΄λ³΄λλ‘νκ² μ΅λλ€.
μ°μ μν κ΄λ¦¬λ μ νμν κΉμ? μΉμμλ μν λ³νκ° λ°μνλ μν©μ ν¬κ² λ€μκ³Ό κ°μ΅λλ€.
- μμ ν΄λ¦, form μ μΆ λ± μ¬μ©μ νμμ μν UI μν λ³ν
- HTTP μμ² λ° μλ΅κ³Ό κ°μ μ»΄ν¨ν μμμ μν UI μν λ³ν
μ΄μ κ°μ΄ μ»΄ν¬λνΈ λ³ λ°μνλ μ¬λ¬ μν λ³νλ₯Ό Reactμμλ hookμ ν΅ν΄ μν λ³μλ₯Ό μ μ§μν¬ μ μμ΅λλ€. useState
λ₯Ό ν΅ν΄ μν μ μ΄λ₯Ό μ μΈν μ μμΌλ©°, useEffect
λ₯Ό ν΅ν΄ React μλͺ
μ£ΌκΈ°μμ μΌμ΄λλ μν λ³νλ κ°μ§ν μ μμ΅λλ€.
const [inputContent, setInputContent] = useState('');
const [error, setError] = useState(null);
hook
μ νΉμ§μ λ€μκ³Ό κ°μ΅λλ€.
μ»΄ν¬λνΈ ν¨μ λ΄μμ λ λλ§ κ° μνλ₯Ό μ μ§μν€κ³ 보κ΄νλ€.
κ° μν λ³μμ μΈμ€ν΄μ€λ κ³ λ¦½λμ΄ μμΌλ―λ‘, κ° μ»΄ν¬λνΈμμ μν λ³μλ₯Ό μ μΈνκ³ μ¬λ¬ λ² νΈμΆνμ¬ μνλ₯Ό λ³κ²½νλλΌλ λ€λ₯Έ μ»΄ν¬λνΈμκ² μν₯μ μ£Όμ§ μμ΅λλ€.
μν μ€μ ν¨μλ₯Ό ν΅ν΄ λ³μ μ
λ°μ΄νΈμ μ»΄ν¬λνΈ λ¦¬λ λλ§μ λ°μ
Reactμμλ hook νΈμΆ κ·μΉμ ν΅ν΄ μνλ₯Ό 체κ³μ μΌλ‘ κ΄λ¦¬ν©λλ€. μ΄λ₯Ό ν΅ν΄ λ©λͺ¨λ¦¬μ hookμ μ°κ΄μ±μ μ μ§ν μ μμ΅λλ€.
μ¬μ©μλ Reactμμ μ 곡λ hookμ μ¬μ©νκΈ°λ§νλ©΄ λ©λλ€. λ¬Όλ‘ , React λ΄λΆμμλ μλμ κ°μ΄ μν κ°μ§λ₯Ό μν΄ useState ν¨μλ₯Ό ꡬνν΄λμμ΅λλ€.
//react@16.13.1/
function useState(initialState) {
var dispatcher = resolveDispatcher();
return dispatcher.useState(initialState);
}
//react-dom@16.13.1
function mountState(initialState) {
var hook = mountWorkInProgressHook();
if (typeof initialState === 'function') {
// $FlowFixMe: Flow doesn't like mixed types
initialState = initialState();
}
hook.memoizedState = hook.baseState = initialState;
var queue = (hook.queue = {
pending: null,
dispatch: null,
lastRenderedReducer: basicStateReducer,
lastRenderedState: initialState
});
var dispatch = (queue.dispatch = dispatchAction.bind(null, currentlyRenderingFiber$1, queue));
return [hook.memoizedState, dispatch];
}
resolveDispatch()
ν¨μλ νμ¬ λ λλ§ μ€μΈ μ»΄ν¬λνΈμ λν λ΄λΆ μ°Έμ‘°λ₯Ό λ°νν©λλ€. μ΄ ν¨μλ₯Ό ν΅ν΄ μ»΄ν¬λνΈκ° λ§μ΄νΈλ λ mountState ν¨μλ₯Ό νΈμΆνκ³ , λ λλ§λ λ updateState ν¨μλ₯Ό ν΅ν΄ μνλ₯Ό λ³κ²½μν΅λλ€.
μ€μν κ²μ λͺ¨λ λ΄λΆμ μΌλ‘ μΌμ΄λκ³ μλ μΌμ΄κΈ° λλ¬Έμ λͺ¨λ κ³Όμ μ μ νμκ° μμ΅λλ€. λμ λ 벨μ μΆμνλ₯Ό ν΅ν μ μΈμ μ½λλ₯Ό μ΄λ£¨κ³ μκΈ° λλ¬Έμ κ°λ°μλ μΈν°νμ΄μ€ κ·μΉμ λ§μΆ° νΈνκ² μ¬μ©λ§ νλ©΄ λ©λλ€.
Reactκ° μ μΈμ μμΌλ‘μ¨ μ»κ²λ μ₯μ λ€
κ°λ μ±κ³Ό μ μ§λ³΄μμ±
κ°λ°μλ μνλ UIμ μ΅μ’ μνλ₯Ό μ μΈμ μΌλ‘ μμ±νκ³ , Reactλ λ΄λΆμ μΌλ‘ ν΄μνμ¬ UIλ₯Ό μ λ°μ΄νΈν©λλ€. μ΄λ₯Ό ν΅ν΄ μ½λμ μλ νμ μ΄ μ¬μμ§λ©°, λ³κ²½ μ¬νμ λν μμ μ΄ μ©μ΄ν΄μ Έ μ μ§ λ³΄μμ±μ΄ ν₯μλ©λλ€.
μ¬μ¬μ©μ±
μ μΈμ μΈ μ½λλ λ 립μ μΈ μ»΄ν¬λνΈλ‘ ꡬμ±λμ΄ μμΌλ©°, μνκ° λ³κ²½λμ΄ μλλΌλ κ³ λ¦½λ μΈμ€ν΄μ€ hookμ ν΅ν΄ λ€λ₯Έ λΆλΆμμ μ¬μ¬μ©νλ λ° λ¬Έμ κ° μμ΅λλ€.
ν¨μ¨μ μΈ κ΄λ¦¬
Reactλ μ μΈμ APIλ₯Ό μ 곡νκΈ° λλ¬Έμ μ
λ°μ΄νΈν λλ§λ€ 무μμ΄ λ³κ²½λλμ§μ λν΄ μ κ²½ μΈ νμκ° μμ΅λλ€. reconciliation
κ³Όμ μ ν΅ν΄ μ체μ μΈ diff μκ³ λ¦¬μ¦μΌλ‘ μλ‘ λ€λ₯Έ νΈλ¦¬λ₯Ό λΉκ΅νκ³ κ°±μ ν©λλ€.