已经有好几个好答案,但是我认为它们的解释不够好,给出的几种方法包含一些可能使人们绊倒的陷阱。因此,我将介绍三种主要方法(外加一个脱题选项)并说明其优缺点。我主要是在写这篇文章,因为大量推荐了选项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,渲染等代码很昂贵,那么它将大大减慢显示组件的速度。这也意味着您不能将其与有状态组件一起使用,在状态组件中,您希望状态在隐藏时得以保留(在显示时得以恢复)。一个优点是,直到选择了隐藏组件,它才被创建。因此,隐藏的组件不会延迟您的初始页面加载。在某些情况下,您可能希望在切换时想重置有状态组件。在这种情况下,这是您的最佳选择。
选项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很好,可能是最好的选择。
但是,如果页面加载缓慢是个问题,则意味着您在生命周期方法中拥有昂贵的代码,通常这不是一个好主意。您可以并且可能应该通过将昂贵的代码移出生命周期方法来解决页面加载缓慢的问题。将其移动到由ComponentDidMount启动的异步函数中,并使回调函数通过setState()将其置于状态变量中。如果状态变量为null且组件可见,则使render函数返回一个占位符。否则渲染数据。这样,页面将快速加载并在标签页加载时填充。您也可以将逻辑移到父级中,并将结果作为道具推送给子级。这样,您可以确定首先加载哪些选项卡的优先级。或缓存结果,仅在第一次显示组件时运行逻辑。
选项3:隐藏课程
类隐藏可能是最容易实现的。如前所述,您只需创建一个带有display:none的CSS类,然后根据prop分配该类。缺点是每个隐藏组件的整个代码都被调用,所有隐藏组件都附加到DOM。(选项1根本不会创建隐藏的组件。选项2在隐藏组件时会短路不必要的代码,并将组件从DOM中完全删除。)根据注释者进行的一些测试,这似乎在切换可见性方面更快。其他答案,但我无法接受。
选项4:一个组成部分,但更改道具。也许根本没有任何组件可以缓存HTML。
这个解决方案不适用于所有应用程序,因此不在主题之列,因为它与隐藏组件无关,但是对于某些用例,这可能是比隐藏更好的解决方案。假设您有标签。可能可以编写一个React组件,而仅使用道具来更改选项卡中显示的内容。您还可以将JSX保存为状态变量,并使用道具决定在render函数中返回哪个JSX。如果必须生成JSX,则执行该操作并将其缓存在父级中,然后发送正确的作为道具。或在子代中生成并以子代状态缓存它,并使用道具选择活动的子代。