(React 공식문서의 main concepts 번역 글입니다.)
함께보면 이해가 쏙쏙 https://youtu.be/xJUrYPAjLwY
React는 encapsulate를 통해서 필요한 동작만 수행하는
독립적인 component를 만들 수 있다.
게다가 state 값에 따라 그 component들 중에
원하는 component만 선택적으로 rendering 할 수 있다.
React에서 conditional rendering은 javascript에서 조건문과 비슷하다.
if
혹은 conditional operators
를 활용하여
현재 state 값을 화면에 나타내는 component를 만들어보자.
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
state 값에 따라 선택적으로 보여줄 2개의 component를 만들었다.
위 component들을 conditional rendering할 큰 component를 만들자.
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />
}
return <GuestGreeting />
ReactDOM.render(
//Try changing to isLoggedIn={true};
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
}
위 Greeting component는 props인 isLoggedIn의 값에 따라
선택적으로 component를 rendering 한다.
react element를 변수에 저장할 수 있다.
이를 통해 component에서 바뀌는 부분(element) 만 render할 수 있다.
아래 2개의 component를 보자.
function LoginButton(props) {
return (
<button onClick={props.onClick}>
Login
</button>
);
}
function LogoutButton(props) {
return (
<button onClick={props.onClick}>
Logout
</button>
);
}
위 2개 button element를 conditional rendering 하는 LoginControl component를 만들 것이다.
LoginControl은 state를 가지고 있다.
그 state 값은 login 여부를 판별한다.
이 state 값에 따라서 다른 button element를 render 할 것이다.
또한 위에서 선언한 Greeting의 return 값인 element도
state 값에 따라 다르게 render 할 것이다.
class LoginControl extends React.component {
constructor(props) {
super(props)
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true})
}
handleLogoutClick() {
this.setState({isLoggedIn: false})
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if(isLoggedIn) { button = <LogoutButton onClick={this.handleLogoutClick} />; } else { button = <LoginButton onCLickc={this.handleLoginClick} />; }
return (
<div>
<Greeting isLoggedIn={isLoggedIn} /> {button} </div>
)
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
변수와 if문을 통해 conditional rendering을 구현할 수 있지만
더 짧은 구현 방법은 없나? 고민할 수 있다.
JSX를 활용한 더 짧은 conditional rendering 구현 방법들이 있다.
JSX inline을 활용한 conditional rendering 구현 방법은 2가지이다.
{}을 사용하면 어떠한 javascript도 JSX안에 넣을 수 있다.
&& 도 마찬가지로 가능하다.
&& 는 특정 react element를 포함하여 render할지 여부를 결정할 때
간단하게 사용할 수 있는 operator이다.
function MailBox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
)
}
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<Mailbox unreadMessages={messages} />,
document.getElementById('root')
);
javascript에서 &&의 동작원리는
true && expressions
는 expressions
를 값으로 가지고
false && expressions
는 false
를 값으로 가진다.
그 결과 조건문, 즉 unreadMessages.length > 0
이 true
면
뒤에 나오는 <h2>
tag가 포함한 내용이 표시될 것이다.
(만약 조건문이 fasle
면 뒤에 나오는 tag는 무시될 것이다.)
javascript 3항 연산자로도 구현이 가능하다
아래는 간단한 text를 표현할 때 3항 연산자를 사용한 예시이다.
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div>
);
}
아래는 react element를 다르게 표현할 때 3항 연산자를 사용한 경우다.
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? ( <LogoutButton onClick={this.handleLogoutClick} />
) : ( <LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
3항 연산자 혹은 if 등의 방법 중 읽기 쉬운 것을 선택하면 된다. 조건이 복잡해질 때는 component를 extract하는 것이 좋다.
특정 component가 다른 component의 render() 안에서 호출되었지만
안 보이게 만들고 싶은 경우가 있다.
이런 경우에는 그 특정 component가 null을 return 하면 된다.
그 결과 특정 component는 호출은 되었지만 null이므로 보이지 않게 된다.
function WarningBanner(props) {
if (!props.warn) {
return null; }
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} /> <button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
분명 WarningBanner는 render()안에서 호출되었지만
warn의 값에 따라서 보이지 않게 될 수 있다.
(warn의 값이 false일 경우 null을 return 하므로)
render()안에서 null값을 return하는 것도 component에게는 update이다.
따라서 해당 component의 lifecycle method에 영향을 준다.
(즉, WarningBanner가 보이지 않게 되는 것은 Page에게 update이므로
WarningBanner가 보이거나 보이지 않게 될 때마다
Page안에서 componentDidUpdate
가 call된다.)