我试图在像这样的无状态组件中切换div的可见性:
const playerInfo = (props) => {
let isPanelOpen = false;
return (
<div onClick={() => isPanelOpen = !isPanelOpen }>Toggle</div>
{isPanelOpen && <div className="info-panel">
{this.props.children}
</div>}
);
};
我发现isPanelOpen
的值更改为true
,但面板未显示。我假设这是因为这是无法再次调用的无状态函数,所以一旦我们返回jsx,它将具有false
的值,并且稍后不会更新它。
有没有办法解决这个问题,并避免通过另外4个父无状态组件来修改这个单个变量作为道具?
答案 0 :(得分:5)
您无法通过直接为变量分配新值来告诉React重新呈现UI(在您执行isPanelOpen = !isPanelOpen
的情况下)。
正确的方法是使用setState
。
但你无法在无状态组件中执行此操作,必须在有状态组件中执行此操作,因此您的代码应如下所示
import React, {Component} from 'react';
class playerInfo extends Component {
constructor(props){
super(props);
this.state = {
isPanelOpen: false
}
}
render() {
return (
<div onClick={() => this.setState({isPanelOpen: !this.state.isPanelOpen})}>Toggle</div>
{this.state.isPanelOpen && <div className="info-panel">
{this.props.children}
</div>}
);
}
}
记住两件事:
1)您的UI只应绑定到this.state.XXXX
(对于有状态组件)或props.XXX
(对于无状态组件)。
2)更新UI的唯一方法是调用setState()
方法,没有其他方法会触发React重新呈现UI。
setState
方法?ONE ANSWER :无状态组件应该包含在另一个有状态组件中。
例让我们说你的无状态组件被称为Kid
,你有另一个名为Mum
的有状态组件。
import React, {Component} from 'react';
class Mum extends Component {
constructor(props){
super(props);
this.state = {
isHappy: false
}
}
render() {
return (
<div>
<button onClick={() => this.setState({isHappy: true})}>Eat</button>
<Kid isHappy={this.state.isHappy}/>
</div>
);
}
}
const Kid = (props) => (props.isHappy ? <span>I'm happy</span> : <span>I'm sad</span>);
答案 1 :(得分:1)
我认为这是因为这是无法再次调用的无状态函数
基本上,重新渲染组件的唯一方法是更改状态或道具。 :)
因此,当您更改本地变量时,React不会收到有关它的通知,也不会启动reconcilation。
答案 2 :(得分:1)
您可以使用本机Javascipt执行此操作,否则在React中您无法使用无状态组件执行此操作:)
const playerInfo = (props) => {
let isPanelOpen = false;
return ( <
div onClick = {
() => {
if (document.getElementsByClassName("info-panel")[0].style.display == 'none') {
isPanelOpen = true;
document.getElementsByClassName("info-panel")[0].style.display = '';
} else {
isPanelOpen = false;
document.getElementsByClassName("info-panel")[0].style.display = 'none';
}
}
} > Toggle < /div> <
div className = "info-panel" > {
this.props.children
} <
/div>
);
};
答案 3 :(得分:1)
您可以通过使用useState挂钩来做到这一点:
import { useState } from "react";
function playerInfo () {
const [panel, setPanel] = useState(false);
function toggleButton () {
if(!panel) setPanel(true);
else setPanel(false);
}
return (
<div>
<button onClick={toggleButton}>Toggle</div>
panel ? {this.props.children} : null;
</div>}
);
};
export default playerInfo;
答案 4 :(得分:0)
除非先前的父状态发生更改并传递向下传播到功能组件的更新属性,否则功能组件不会重新呈现。您可以从有状态父级传递onClick处理程序,并在触发onClick时从无状态组件中调用它。父母将控制显示的切换并将其作为道具传递给孩子(参见下面的片段)。
要构建此功能,您应确定您的HOC(更高阶组件)是否应该负责UI状态。如果是这样,那么它可以确定其子组件是否应该处于打开状态,然后将其作为属性传递给子状态。如果这是一个应该独立于周围世界而打开和关闭的组件,那么它应该有自己的状态。例如,如果您正在创建一个选项卡式窗口小部件,它应该可以控制自己的打开和关闭状态。
class App extends React.Component {
state= {
isOpen: false
}
handleClick = () => {
this.setState({
isOpen: !this.state.isOpen
})
}
render() {
return (
<div>
<YourComponent isOpen={this.state.isOpen} handleClick={this.handleClick} />
</div>
)
}
}
const YourComponent = ({isOpen, handleClick} = props) => {
const onClick = () => {
if (handleClick) {
handleClick();
}
}
return (
<div onClick={onClick}>
{isOpen ?
<h2>it is open</h2>
:
<h2>it is closed</h2>
}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
&#13;
如果你主要关注的是将属性/方法传递给太多的组件,你可以创建一个pure component,它可以让你访问状态但不是React Component子类的所有开销。您还可以考虑使用像Redux这样的状态管理工具。
答案 5 :(得分:0)
从React的16.8版本开始,您可以使用钩子(在这种情况下为useState
)来处理无状态组件。以最简单的形式,它可以这样实现:
import React, { useState } from 'react';
const PlayerInfo = (props) => {
const [showPanel, togglePanel] = useState(false);
return (
<div onClick={() => togglePanel(!showPanel) }>Toggle</div>
{showPanel && (
<div className="info-panel">
{props.children}
</div>
)}
</div>
);
};
export default PlayerInfo;