我正在尝试构建一个简单的动态更新的交互式列表,当您单击它们时,该列表根据.clicked类的css规则设置每个<li></li>
的样式。
该应用程序由两个组件组成,一个父组件和一个子组件,有问题的代码如下(取自子组件(:
handleClick(e) {
document.getElementById(e.currentTarget.id).setAttribute("class","clicked");
}
render() {
let ar = this.props.sentences;
let pro = ar.map((x,i)=>{ return (<li id={i} key={i} className={i%2==0 ? "white" : "grey"}
onClick={this.handleClick}>{x}</li>); })
return (
<div>
<ul id="ul">{ pro }</ul>
</div>
这里发生的事情基本上是父母向子级传递一个句子道具(一个句子数组,将构成形成动态列表的基础(。
有争议的部分是我以document.getElementById(e.currentTarget.id).setAttribute("class","two");
的形式使用 DOM 操作来更改从 jsx 动态创建的 html 的类。
上面的代码有效,但它不是最佳实践。使用 react 的全部优势是使用虚拟 dom 并优化 DOM 的更新方式。
我的问题如下:
1(我有这种感觉是对的吗?(我的解决方案不是最佳实践?
2( (如果是这样, (如何构建我的代码以使用虚拟 dom 机器 react 提供的?
如果您知道这个问题是重复的,请发表评论,我会将其删除。
1(我有这种感觉是对的吗?(我的解决方案不是最佳实践?
假设这不是一个理想的方法是正确的,通过 React 中的 vanilla js 操作 DOM 有它的位置(示例用例(,但除非绝对必要,否则不应该这样做。 此外,使用Array.prototype.map
中的索引作为组件上的键是不理想的,因为如果它们改变顺序可能会导致 React 混淆,因为在这种情况下键的映射方式会有所不同。
2( (如果是这样, (如何构建我的代码以使用虚拟 dom 机器 react 提供的?
您应该利用组件状态。如果希望每个单击的元素都维护clicked
类,则创建一个状态来缓存已收到clicked
类的元素。 如果只有最近单击的元素获取clicked
类,则只需将标识符缓存到状态中的相应元素即可。您也可以为此目的使用refs,尽管Facebook不鼓励过度使用它们。
这是一个快速截图,它将在每个<li>
上切换click
类
class Test extends Component {
constructor() {
super();
this.state = {
clicked: {}
};
}
render() {
let ar = this.props.sentences;
let pro = ar.map((x, i) => {
const color_class = i % 2 === 0 ? "white" : "grey";
const clicked_class = this.state.clicked[i] === true ? "clicked" : "";
let clicked = Object.assign({}, this.state.clicked); // Dont mutate state!!!
return (
<li
id={i}
key={i}
className={`${color_class} ${clicked_class}`}
onClick={e => {
if (clicked.hasOwnProperty(i)) {
delete clicked[i];
} else {
clicked[i] = true;
}
this.setState({ clicked });
}}
>
{x}
</li>
);
});
return (
<div>
<ul id="ul">
{pro}
</ul>
</div>
);
}
}