【发布时间】:2020-04-29 19:13:21
【问题描述】:
我已经四处寻找答案——我发现最接近的是this question——但我认为我的情况有很大的不同(事实上它开始进入持有其孩子状态的父母...孩子们)这最终导致我要求澄清。
我的意思的一个非常简单的例子如下(希望能更好地说明我的要求):
假设我们有一堆类似的书籍文档
bookList = [
{
title: "book 1",
author: "bob",
isbn: 1,
chapters: [
{ chapterNum: 1, chapterTitle: "intro", chapterDesc: "very first chapter", startPg: 2, endPg: 23 },
{ chapterNum: 2, chapterTitle: "getting started", chapterDesc: "the basics", startPg: 24, endPg: 45 }
]},
{
title: "book 2" ... }
]
所以重点是文档中的这些嵌入对象可能很长,因此可能会折叠/展开。
然后这里是显示组件的粗略代码示例
class App extends Component {
constructor(props) {
super(props);
this.state = {
books: bookList,
focusBook: null
}
this.updateDetailDiv = this.updateDetailDiv.bind(this);
}
updateDetailDiv(book) {
this.setState(
{ focusBook: book}
);
}
render() {
return(
<BookList
bookList = {this.state.books}
updateDetailDiv = { this.updateDetailDiv }
/>
<BookDetail
focusBook = { this.state.focusBook }
/>
);
}
}
const BookList = props => {
return (
props.bookList.map(item=>
<li onClick={()=> props.updateDetailDiv(item)}> {item.title} </li>
)
);
}
const BookDetail = props => {
return (
<div className="bookDetails">
{ props.focusBook != null
? <div>
{props.focusBook.title},
{props.focusBook.author},
{props.focusBook.isbn}
Chapters:
<div className="chapterList">
{ props.focusBook.chapters.map(item=>
<span onClick={()=>someFunction(item)}>{item.chapterNum} - {item.chapterName}</span>
)}
</div>
<div id="chapterDetails">
This text will be replaced with the last clicked chapter's expanded details
</div>
</div>
: <div>
Select A Book
</div>
})
}
someFunction(item) {
document.getElementById('chapterDetails').innerHTML = `<p>${item.chapterDesc}</p><p>${item.startPg}</p><p>${item.endPg}</p>`;
}
所以我的问题是我不确定在不将其传递给父组件的情况下处理功能性无状态组件中数据的简单外观/视觉更改的最佳方法是什么——这对第一个孩子来说很好并且有意义- 但是当许多孩子都有自己的孩子(他们可能有自己的孩子)时会发生什么--> 都需要自己的渲染选项? 例如 - 此处 App 组件将重新渲染 DetailDiv 组件(因为状态已更改) - 但我不希望 App 也处理 DetailDiv 的详细 div。在我的示例中,这一切都非常简单,但我正在处理的实际应用程序具有 2 或 3 层嵌入式项目——一旦由 App 呈现——实际上可以通过普通 JS 直观地修改。
所以在我的示例中,您会看到我在每个章节列表中都有一个 someFunction() - 我可以通过编写一个单独的简单“传统 JS DOM 函数”来完成这项工作(即:target.getElementById 或 closest() --但我不认为我应该在使用 React 时使用普通的 JS 来操作 DOM。
再次总结一下——对无状态组件的渲染输出进行简单的 DOM 操作的最佳方式是什么?将这些变成自己的类似乎有点过头了——让“父”应用程序处理它的“孙子”和“曾孙”状态将随着应用程序的增长而变得笨拙。我一定错过了一个明显的例子,因为在没有状态组件层的情况下,我没有看到太多处理这个问题的方法。
编辑为清楚起见:
BookDetail 是一个无状态组件。
父有状态组件将对象作为道具传递给它(App)
当App的状态发生变化时,它会再次渲染,反映变化。
假设BookDetail负责显示大量数据。
我想要它,这样BookDetail 中的每个span 在单击时都会在chapterDetail div 中显示其相关的item。
如果单击另一个span,则chapterDetail div 将填充那个 item 的详细信息。 (这只是一个简单的例子——它可以是对某个无状态组件的任何其他纯外观更改——在这种情况下,父母必须跟踪它似乎有点过分了)
我不知道如何在渲染后更改无状态组件的 UI/外观而不给它状态或让父级跟踪本质上是“子状态”的内容(因为这是更新外观的唯一方法组件的状态是改变其状态,触发渲染)。
有没有办法在不使 BookDetail 成为有状态组件的情况下做到这一点?
【问题讨论】:
-
您的“问题”很难理解。 Presentation/UI 实际上与具有或不具有内部状态的组件无关。是的,在 React 中操作 DOM 是一种反模式。你能更清楚(即明确)你想要做什么吗?
-
您好,我试图清除它。
-
好的,听起来你有一个映射“章节”组件数组的“书籍详细信息”组件,当单击“章节”时,您想要它打开章节详细信息。假设您在任何给定时间只想要一个“章节”“打开/扩展”是否安全? 或根据您的原始措辞,您有一个章节列表,单击特定章节后,该章节的详细信息会显示在“chapterDetails”div 中?其中一个听起来正确吗?
-
嘿,是的,两者的结合非常接近 - 一个
BookDetail组件,它映射一个“章节”、“按钮”(或跨度,或任何可点击的)数组,当一个“章节”是点击后,那个章节的详细信息会显示在 chapterDetails div 中。 (在任何给定时间只有一个)