すでにいくつかの素晴らしい答えがありますが、それらは十分に説明されていないと思います、そして与えられた方法のいくつかは人々をつまずかせるかもしれないいくつかの落とし穴を含んでいます。そのため、これを行うために3つの主要な方法(およびトピック外のオプションを1つ)を検討し、長所と短所を説明します。オプション1が多く推奨されており、正しく使用しない場合、そのオプションには多くの潜在的な問題があるので、私は主にこれを書いています。
オプション1:親での条件付きレンダリング。
コンポーネントを1回だけレンダリングしてそのままにしない限り、この方法は好きではありません。問題は、可視性を切り替えるたびにコンポーネントを最初から作成する反応が発生することです。これがその例です。LogoutButtonまたはLoginButtonは、条件付きで親LoginControlにレンダリングされます。これを実行すると、ボタンがクリックされるたびにコンストラクターが呼び出されることがわかります。https://codepen.io/Kelnor/pen/LzPdpN?editors=1111
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 = null;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
class LogoutButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created logout button');
}
render(){
return (
<button onClick={this.props.onClick}>
Logout
</button>
);
}
}
class LoginButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created login button');
}
render(){
return (
<button onClick={this.props.onClick}>
Login
</button>
);
}
}
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
これで、Reactはコンポーネントを最初から作成するのがかなり速くなりました。ただし、作成時にコードを呼び出す必要があります。そのため、コンストラクタ、componentDidMount、renderなどのコードが高価な場合、コンポーネントの表示が大幅に遅くなります。これはまた、非表示のときに状態を保持したい(表示したときに復元したい)ステートフルコンポーネントではこれを使用できないことを意味します。1つの利点は、非表示のコンポーネントが選択されるまでまったく作成されないことです。したがって、非表示のコンポーネントが最初のページの読み込みを遅らせることはありません。トグルしたときにリセットするステートフルコンポーネントが必要な場合もあります。この場合、これが最良のオプションです。
オプション2:子の条件付きレンダリング
これにより、両方のコンポーネントが一度作成されます。次に、コンポーネントが非表示の場合、残りのレンダーコードを短絡します。可視プロップを使用して、他の方法で他のロジックを短絡することもできます。codepenページのconsole.logに注目してください。https://codepen.io/Kelnor/pen/YrKaWZ?editors=0011
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;
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
<LoginButton isLoggedIn={isLoggedIn} onClick={this.handleLoginClick}/>
<LogoutButton isLoggedIn={isLoggedIn} onClick={this.handleLogoutClick}/>
</div>
);
}
}
class LogoutButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created logout button');
}
render(){
if(!this.props.isLoggedIn){
return null;
}
return (
<button onClick={this.props.onClick}>
Logout
</button>
);
}
}
class LoginButton extends React.Component{
constructor(props, context){
super(props, context)
console.log('created login button');
}
render(){
if(this.props.isLoggedIn){
return null;
}
return (
<button onClick={this.props.onClick}>
Login
</button>
);
}
}
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
これで、初期化ロジックが高速で、子がステートレスである場合、パフォーマンスや機能の違いはわかりません。しかし、なぜとにかくReactがトグルのたびにまったく新しいコンポーネントを作成するようにするのですか?ただし、初期化に負荷がかかる場合は、コンポーネントを切り替えるたびにオプション1が実行され、切り替え時にページが遅くなります。オプション2は、最初のページのロード時にコンポーネントのすべての初期化を実行します。最初のロードを遅くします。再度注意する必要があります。条件に基づいてコンポーネントを1回だけ表示してトグルしない場合、またはtoggledmのときにコンポーネントをリセットしたい場合は、オプション1が適切で、おそらく最良のオプションです。
ただし、ページの読み込みが遅いことが問題である場合は、ライフサイクルメソッドに高額なコードが含まれていることを意味します。高価なコードをライフサイクルメソッドの外に移動することで、ページの遅い読み込みを解決できます。これを、ComponentDidMountによって開始された非同期関数に移動し、コールバックでsetState()を使用して状態変数に入れます。状態変数がnullでコンポーネントが表示されている場合、render関数にプレースホルダーを返させます。それ以外の場合は、データをレンダリングします。これにより、ページがすばやく読み込まれ、タブが読み込まれるときにタブが表示されます。ロジックを親に移動して、結果を小道具として子にプッシュすることもできます。これにより、最初にロードされるタブに優先順位を付けることができます。または、結果をキャッシュして、コンポーネントが初めて表示されたときにのみロジックを実行します。
オプション3:クラス非表示
クラス非表示はおそらく実装が最も簡単です。前述のように、display:noneを使用してCSSクラスを作成し、propに基づいてクラスを割り当てます。欠点は、すべての非表示コンポーネントのコード全体が呼び出され、すべての非表示コンポーネントがDOMにアタッチされることです。(オプション1は非表示コンポーネントをまったく作成しません。オプション2は、コンポーネントが非表示になると不要なコードを短絡し、コンポーネントをDOMから完全に削除します。)これは、他の答えは、私はそれについて話すことができません。
オプション4:1つのコンポーネントですが、小道具を変更します。または、コンポーネントがまったくなく、HTMLをキャッシュします。
これはすべてのアプリケーションで機能するわけではなく、コンポーネントを非表示にすることではないため、トピックから外れていますが、一部のユースケースでは非表示にするよりも優れたソリューションである可能性があります。タブがあるとしましょう。1つのReactコンポーネントを記述し、プロップを使用してタブに表示されるものを変更することもできます。また、JSXを状態変数に保存し、propを使用して、レンダー関数で返すJSXを決定することもできます。JSXを生成する必要がある場合は、JSXを生成して親にキャッシュし、正しいものをプロップとして送信します。または、子で生成し、子の状態でキャッシュし、小道具を使用してアクティブな子を選択します。