Đã có một số câu trả lời tuyệt vời, nhưng tôi không nghĩ rằng chúng đã được giải thích rất rõ và một số phương pháp được đưa ra có chứa một số vấn đề có thể khiến mọi người gặp rắc rối. Vì vậy, tôi sẽ đi qua ba cách chính (cộng với một tùy chọn ngoài chủ đề) để làm điều này và giải thích những ưu và nhược điểm. Tôi chủ yếu viết thư này vì Tùy chọn 1 được đề xuất rất nhiều và có rất nhiều vấn đề tiềm ẩn với tùy chọn đó nếu không được sử dụng đúng cách.
Tùy chọn 1: Kết xuất có điều kiện trong cha mẹ.
Tôi không thích phương pháp này trừ khi bạn chỉ kết xuất thành phần một lần và để nó ở đó. Vấn đề là nó sẽ gây ra phản ứng để tạo ra thành phần từ đầu mỗi khi bạn bật chế độ hiển thị. Đây là ví dụ. LogoutButton hoặc LoginButton đang được hiển thị một cách có điều kiện trong tệp cha mẹContControl. Nếu bạn chạy nó, bạn sẽ thấy hàm tạo sẽ được gọi trên mỗi nút bấm. 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')
);
Bây giờ React khá nhanh trong việc tạo các thành phần từ đầu. Tuy nhiên, nó vẫn phải gọi mã của bạn khi tạo nó. Vì vậy, nếu mã xây dựng, mã thành phần, kết xuất, vv của bạn đắt tiền, thì nó sẽ làm chậm đáng kể việc hiển thị thành phần. Điều đó cũng có nghĩa là bạn không thể sử dụng điều này với các thành phần trạng thái nơi bạn muốn trạng thái được bảo tồn khi ẩn (và được khôi phục khi hiển thị.) Một lợi thế là thành phần ẩn hoàn toàn không được tạo cho đến khi được chọn. Vì vậy, các thành phần ẩn sẽ không trì hoãn tải trang ban đầu của bạn. Cũng có thể có trường hợp bạn MUỐN một thành phần trạng thái để đặt lại khi bật. Trong trường hợp này đây là lựa chọn tốt nhất của bạn.
Tùy chọn 2: Kết xuất có điều kiện ở trẻ
Điều này tạo ra cả hai thành phần một lần. Sau đó ngắn mạch phần còn lại của mã kết xuất nếu thành phần bị ẩn. Bạn cũng có thể đoản mạch logic khác trong các phương pháp khác bằng cách sử dụng prop có thể nhìn thấy. Lưu ý console.log trong trang codepen. 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')
);
Bây giờ, nếu logic khởi tạo nhanh và trẻ em không trạng thái, thì bạn sẽ không thấy sự khác biệt về hiệu suất hoặc chức năng. Tuy nhiên, tại sao làm cho React tạo ra một thành phần hoàn toàn mới mỗi lần chuyển đổi? Tuy nhiên, nếu việc khởi tạo tốn kém, Tùy chọn 1 sẽ chạy nó mỗi khi bạn chuyển một thành phần sẽ làm chậm trang khi chuyển đổi. Tùy chọn 2 sẽ chạy tất cả các phần tử của thành phần khi tải trang đầu tiên. Làm chậm tải đầu tiên đó. Nên lưu ý lại. Nếu bạn chỉ hiển thị thành phần một lần dựa trên một điều kiện và không bật / tắt hoặc bạn muốn thiết lập lại khi bật, thì Tùy chọn 1 vẫn ổn và có lẽ là tùy chọn tốt nhất.
Tuy nhiên, nếu tải trang chậm là một vấn đề, điều đó có nghĩa là bạn đã có mã đắt tiền trong phương pháp vòng đời và đó thường không phải là một ý tưởng hay. Bạn có thể, và có lẽ nên, giải quyết tải trang chậm bằng cách di chuyển mã đắt tiền ra khỏi các phương thức vòng đời. Di chuyển nó đến một chức năng không đồng bộ được khởi động bởi ElementDidMount và gọi lại đặt nó vào một biến trạng thái với setState (). Nếu biến trạng thái là null và thành phần hiển thị thì có chức năng kết xuất trả về một trình giữ chỗ. Nếu không thì kết xuất dữ liệu. Bằng cách đó, trang sẽ tải nhanh và điền vào các tab khi chúng tải. Bạn cũng có thể di chuyển logic vào phụ huynh và đẩy kết quả cho trẻ làm đạo cụ. Bằng cách đó bạn có thể ưu tiên các tab nào được tải trước. Hoặc lưu trữ kết quả và chỉ chạy logic khi lần đầu tiên một thành phần được hiển thị.
Lựa chọn 3: Ẩn lớp
Lớp ẩn có lẽ là dễ thực hiện nhất. Như đã đề cập, bạn chỉ cần tạo một lớp CSS có hiển thị: không có và gán lớp dựa trên prop. Nhược điểm là toàn bộ mã của mọi thành phần ẩn được gọi và tất cả các thành phần ẩn được đính kèm vào DOM. (Tùy chọn 1 hoàn toàn không tạo ra các thành phần ẩn. Và Tùy chọn 2 ngắn mạch mã không cần thiết khi thành phần bị ẩn và loại bỏ hoàn toàn thành phần khỏi DOM.) Có vẻ như điều này nhanh hơn trong việc chuyển đổi khả năng hiển thị theo một số thử nghiệm được thực hiện bởi các nhà bình luận trên câu trả lời khác nhưng tôi không thể nói điều đó.
Tùy chọn 4: Một thành phần nhưng thay đổi Đạo cụ. Hoặc có thể không có thành phần nào cả và bộ đệm HTML.
Ứng dụng này sẽ không hoạt động cho mọi ứng dụng và nó không có chủ đề vì nó không phải là để ẩn các thành phần, nhưng nó có thể là một giải pháp tốt hơn cho một số trường hợp sử dụng hơn là ẩn. Hãy nói rằng bạn có các tab. Có thể viết một Thành phần Phản ứng và chỉ cần sử dụng các đạo cụ để thay đổi những gì được hiển thị trong tab. Bạn cũng có thể lưu JSX vào các biến trạng thái và sử dụng prop để quyết định JSX nào sẽ trả về trong hàm kết xuất. Nếu phải tạo ra JSX thì hãy thực hiện nó và lưu trữ nó trong tệp cha và gửi chính xác dưới dạng prop. Hoặc tạo trong đứa trẻ và lưu trữ nó trong trạng thái của trẻ và sử dụng đạo cụ để chọn một hoạt động.