class OnChange extends Component {
render() {
return (
<div>
email: <input />
password: <input />
</div>
);
}
}
위 예제에는 두개의 인풋이 있다.
사용자가 input 에 입력한 값을 state 저장하려면 어떻게 해야 할까?
class OnChange extends Component {
constructor() {
super();
this.state = {
Email: "",
Pw: "",
}
}
handleEmail = (e) => {
console.log("Email!!") // 우선 함수가 잘 동작하는지 확인하자
this.setState({
Email: e.target.value,
})
}
handlePw = (e) => {
console.log("Pw!!") // 우선 함수가 잘 동작하는지 확인하자
this.setState({
Pw: e.target.value,
})
}
render() {
console.log(this.state); // 최신화된 state 의 값을 콘솔로 확인해본다
return (
<div>
email: <input onChange={this.handleEmail} />
password: <input onChange={this.handlePw} />
</div>
);
}
}
각 input 에 onChange 이벤트를 걸고, state 를 setState() 로 최신화 시켜주면 된다.
이 때 render() 안에서 console.log() 를 하는 이유는 setState() 의 비동기처리 때문에 그때그때 최신화 된 값을 확인할 수 없기 때문이다. setState() 가 실행되면 다시 render() 가 실행되기 때문에 render() 는 항상 최신화된 값을 가지고 있다.
이렇게 각각의 input 에 다른 이벤트를 걸어 따로 값을 가져올 수도 있지만, 하나의 메서드로 두개 이상의 input 을 관리하는 효율적인 방법이 있다.
class OnChange extends Component {
constructor() {
super();
this.state = {
Email: "", // 1번
Pw: "",
}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value, // 2번
})
}
render() {
return (
<div>
email: <input
name="Email" // 3번
onChange={this.handleChange} />
password: <input
name="Pw"
onChange={this.handleChange} />
</div>
);
}
}
일단 두개의 input 이벤트에 하나의 함수를 걸어준다. 이 때 실행되는 함수는 setState() 함수로 [e.target.name]
이라는 key 에 e.target.value
라는 사용자가 입력한 값을 저장한다.
[e.target.name]
는 계산된 속성명이라고 하며, 여기서는 이벤트가 발생한 대상 즉, input 의 name 속성이 무엇인지에 따라 그에 해당하는 key의 값을 setState() 한다.
email input 에 값을 입력하였으면 그 input 의 name 은 Email 일 것이고, Email 이라는 key 의 값이 사용자가 입력한 값이 되는 것이다.
결과는 같지만 내부적으로 효율성이 증가했다. 이제 name 속성을 활용하면 input 태그가 몇개가 있건 하나의 메서드로 관리할 수 있다.
export default class MenuTab extends Component {
render() {
return (
<div className="wrapper">
<ul className="tabs">
<li>First</li>
<li>Second</li>
<li>Third</li>
</ul>
<div className="contents">
<First />
</div>
</div>
);
}
}
우선 위 예제는 아래의 화면을 구성한다. 간단하게 말하자면 First, Second, Third 라는 Tab 을 클릭할 때마다 그에 해당하는 각각의 화면을 사용자에게 보여주고 싶은 상황이다.
우선적으로 사용자가 어떤 Tab 을 클릭했는지 효과적으로 확인할 수 있는 방법은 무엇일까?
export default class MenuTab extends Component {
clickHandler = (id) => {
console.log(id)
};
render() {
return (
<div className="wrapper">
<ul className="tabs">
<li onClick={() => this.clickHandler(0)}>First</li>
<li onClick={() => this.clickHandler(1)}>Second</li>
<li onClick={() => this.clickHandler(2)}>Third</li>
</ul>
<div className="contents">
<First />
</div>
</div>
);
}
}
li 마다 고유의 id 주어서 식별할 수도 있지만, 굳이 그럴 필요 없이 이벤트가 발생하면 실행되는 함수에 고유의 인자를 넣어 보내주면된다.
아래에서 각 Tab을 한번씩 클릭했더니 클릭이벤트가 발생하면 실행되는 함수로 넣어 보내주었던 인자값이 콘솔창에 찍히는 것을 확인할 수 있다.
이렇게 함수에 넣어 보내주었던 인자값을 확인했으니 활용할 수가 있다. 그 인자(id) 를 기존 state 에 업데이트 시켜준 후, 업데이트 된 값(0, 1, 2)에 해당하는 key 를 가진 객체를 component 밖에 선언해 주면 객체의 value 에 접근하는 방식을 사용하여 어떤 메뉴탭을 클릭하냐에 따라 다른 컴포넌트를 렌더링 할 수 있게 된다.
const obj = {
0: <First />,
1: <Second />,
2: <Third />,
}
export default class MenuTab extends Component {
state = {
activeTab: 0,
}
clickHandler = (id) => {
this.setState({
activeTab: id,
})
};
render() {
return (
<div className="wrapper">
<ul className="tabs">
<li onClick={() => this.clickHandler(0)}>First</li>
<li onClick={() => this.clickHandler(1)}>Second</li>
<li onClick={() => this.clickHandler(2)}>Third</li>
</ul>
<div className="contents">
{obj[this.state.activeTab]}
</div>
</div>
);
}
}