我有一个 DynamicRenderApp 组件,它有两种模式滚动和非滚动模式。 如果内部子内容高度超过一定高度(例如:100px),则视图切换为滚动模式,否则为非滚动模式。
class DynamicRenderApp extends React.Component {
constructor() {
this.state = {
scrollMode: false
}
}
// ResizeObserver to update the content when js update is done
obs = new ResizeObserver(() => {
if (this.childWrapperRef.getBoundingClientRect().height > 100) {
this.setState({ scrollMode: true })
}
})
componentDidMount() {
this.obs.observe(this.childWrapperRef);
}
render() {
const { children } = this.props;
this.setState({ scrollMode: this.childWrapperRef.getBoundingClientRect().height > 100 ? true : false })
return (
<DynamicRenderWrapper>
{this.state.scrollMode ? (
// scroll view
<ScrollView>
<childWrapper ref={elem => this.childWrapperRef = elem}>
{
React.Children.map(children, (child) =>
React.cloneElement(child, { ...child.props }))
}
</childWrapper>
</ScrollView>)
:
(
// non-scroll view
<childWrapper ref={elem => this.childWrapperRef = elem}>
{
React.Children.map(children, (child) =>
React.cloneElement(child, { ...child.props }))
}
</childWrapper>
)
}
</DynamicRenderWrapper>
)
}
}
当使用 React setState 进行更新时,DOM 将正确切换视图并且 props.children 得到更新并在组件内呈现。
// storybook
export const renderMyComp = () => {
const updateContent = () => {
// dynamic update using javascript
document.getElementById('dummyId').innerHTML =
'Lorem ipsum, dolor sit amet consectetur adipisicing elit. Vero, reprehenderit numquam';
}
return (
<Fragment>
<DynamicRenderApp>
<h1>heading</h1>
<p id='dummyId'>
This is a dynamic render block
</p>
</DynamicRenderApp>
<button onClick={updateContent}>Update</button>
</Fragment>
)
}
但是当我们使用javascript动态更新内容时,视图在滚动和非滚动视图之间切换。在此转换期间,DOM 将替换为初始状态,props.children 将不会更新为动态内容。
为了解决这个问题,我使用了 ResizeObserver,但是由于 if-else 块,DOM 被替换为初始状态并且动态变化丢失了。 我们可以在 ResizeObserver 中找到动态内容作为 HTML DOM 集合,但我们需要将其转换为 React 节点,以便我们可以更新 props.children。 那么,有没有办法在完成动态 js 更新或任何其他建议时更新 props.children。