Create React App
을 통해 코드를 실행할 수 있는 환경 설정을 한다..jsx
파일에 form
footer
등 기능별 jsx 코드를 분리하여 App.js
파일을 간결하게 만든다.재활용 가능한 코드로 만들어 중복 기능 함수 제거
form
에서 input
부분(아이디, 비밀번호, 비밀번호 확인 입력칸)은 각각 id
label
type
placeholder
를 제외한 모든 부분이 같기 때문에 4개의 변수를 가져와 하나의 컴포넌트에서 재활용하여 사용할 수 있다.
또한, 한 번에 모든 form
에 효과를 주거나 제어를 할 경우 컴포넌트 하나로 컨트롤 할 수 있다는 장점이 있다.
<FormInput
id={'id'}
label={'아이디'}
inputProps={{
type: 'text',
placeholder: '아이디를 입력해주세요.',
}}
/> //FormInput로 재사용하여 변수로 각각 입력창 대응
컴포넌트화 된 FormInput
의 id
변수가 'id'
일 경우에 오토 포커스 되어야 한다.
props
에 id를 넘겨주는 Form 컴포넌트에서 autoFocus:true
를 추가한다.<FormInput
id={'id'}
label={'아이디'}
inputProps={{
type: 'text',
placeholder: '아이디를 입력해주세요.',
autoFocus: true, //id에만 추가
}}
/>
useEffect
를 사용하여 특정 시점(의존성 부여)에 id
에 포커스가 가도록 한다.//useRef : DOM을 사용할 수 있게 해준다.
const idRef = useRef(null)
useEffect(() => {
if (id === 'id') idRef.current.focus()
}, [])
//input 태그에 ref={idRef} 속성을 부여하고 사용 !
일반적인 DOM 엘리먼트는 사용자 입력이 아닌 React에서 state로 상태를 관리하고 그 상태를 바탕으로 렌더링한다.
폼 엘리먼트의 value
를 props
으로 관리한다면 제어 컴포넌트로 사용하는 것이다. (useState 사용)
언제 무엇을 사용하는가 ?
제어 컴포넌트의 상태(state)를 어떤 레벨에서 관리할 것인가?
Form, FormInput 컴포넌트를 분리했기 떄문에 App.js
에서 state
를 만들어 보낸다면 Form
컴포넌트는 사용하지 않는 상태를 자식과 부모의 징검다리로 연결하기 위해 참조해야 하는데, 이 과정이 반복되는 것을 prop drilling
이라고 한다.
컴포넌트가 복잡해지고 사용하지 않는 참조를 해야하기 때문에 비효율적이므로 전역으로 사용하는 useContext
를 사용하여 구현한다.
//App.js에서 context 생성
const initFormData = {
id: '',
pw: '',
confirmPw: '',
}
export const FormContext = createContext({ //export로 다른 컴포넌트에서 접근 가능
formState: initFormData,
setFormData: () => {},
})
// **************<FormContext.Provider value={{ formData, setFormData }}> //형태로 App함수 만들기
//FormInput.jsx에서 REGEX, MSG, check 함수 등 만들고 return**************
modal
이 showModal, close
되기 위해서는 전체 화면을 제어하는App
에서 useRef
를 사용하여 넘겨준다.ref
를 바로 전달 받을 수 없기 떄문에 forwardRef
를 사용하여 전달 받는다.Modal.jsx
에서 useContext
로 id, pw
정보를 가져온다. (전역)Form.jsx
에서도 modalRef
를 참조하여 클릭시 showModal
메소드를 호출 할 수 있도록 만든다. (이 때 참조하는 값 modalRef는 이름이 ref
가 아니기때문에 forwardRef
처리를 하지 않아도 된다.//App.js
function App() {
const modalRef = useRef(null)
...
<Form modalRef={modalRef}/>
...
<Modal ref={modalRef}/>
//Modal.jsx
const Modal = forwardRef((props, ref) => //ref 전달 시 forwardRef로 전체 감싸기
{ ...
const { formData } = useContext(FormContext) //전역에 있는 id, pw 정보 가져오기
const handleClick = (type) => {
ref.current.close() //modal 창 닫기
type === 'increase' && window.alert('가입되었습니다') //가입 시 알림 창
return (
...
{formData.id} //id 부분에 id를 innerText로 삽입
)
}
//Form.jsx
const Form = ({modalRef}) => { //가입하기 클릭 시 showModal
const handleSubmit = (e) => {
e.preventDefault()
const isValid = Object.valuse(errorData).every(
(value) => value === true //error 없을 시
)
isValid && modalRef.current.showModal()
}
return (
...
<input //가입하기
type="submit"...onClick={handlesubmit}/>
)}
useEffect
useState
를 사용하여 버튼 클릭시 의존적으로 상태를 변경하고 반영하도록 만든다.//FontSizeControl.jsx
const [fontSize, setFontSize] = useState(getHtmlFontSize())
const handleClick = (flag) => {
if (flag === 'increase') setFontSize((prev) => prev + 1)
else setFontSize((prev) => prev - 1)
}
useEffect(() => {
$html.style.fontSize = fontSize + 'px'
}, [fontSize])
//button 속성 부분
<button onClick={() => handleClick('increase')}
disabled={fontSize >= MAX_FONT_SIZE}> </botton>
chrome 확장 프로그램 react developer tool로 렌더링 횟수를 알아볼 수 있다. (효과적인지 아닌지)