React - 对未安装的 JSX 行进行适当的状态管理?

React - proper state management for rows of unmounted JSX?

我们有一个疯狂的 DOM 层次结构,我们一直在 props 中传递 JSX,而不是嵌入子项。我们希望基础 class 管理显示哪些子文档,以及哪些子文档停靠或附加到其关联文档的顶部 window.


问题是我们正在传递深度嵌套的 JSX,状态管理/访问表单中的 refs 是一场噩梦。

我不想每次都重新声明每一行,因为这些行在 Base Class 中附加了附加状态,而 Base Class 需要知道哪些行实际上改变了。如果我不重新声明行,这很容易。


我不知道如何实际处理自定义表单中的 JSX 行。

  1. Refs 只能附加在 render() 的子例程中。如果 CustomForm 想要测量一个 JSX 元素或者写内联 CSS 怎么办?那个 JSX 元素怎么可能存在于 CustomForm.state 中,而且还有一个 ref?我可以 cloneElement 并在 CustomForm 中保留一个虚拟的 DOM(带有 refs),或者依赖于基础 class 来提供深度嵌套的、挂载的 ref
  2. 我认为从现有状态编写组件状态是不好的做法。如果 CustomForm 状态发生变化,并且我想更改传递给 BaseClass 的行,我必须使用 shouldComponentUpdate 进行限制,重新声明该阶段文档(维护行对象引用),然后调用 setState总体集合。 this.state.stages.content[3].jsx 是唯一发生变化的东西,但是当我看到 props.stages 发生变化时,我必须遍历 BaseClass 中每个阶段文档中的每一行。

处理 JSX 集合有什么技巧吗?难道我做错了什么?这一切似乎过于复杂,我宁愿不遵循一些反模式使问题恶化。


自定义表单:

render () {
  return <BaseClass stages={this.stages()}/>
}

stages () {
  if (!this._stages) this._stages = { title: this.title(), content: this.content() };
  return this._stages;
}

title () {
  return [{
    canBeDocked: false,
    jsx: (
      <div>A title document row</div>
    )
  }
}

content () {
  return [{
    canBeDocked: false,
    jsx: (
      <div>Hello World</div>
    )
  }, {
    canBeDocked: true,
    jsx: (
      <div>Yay</div>
    )
  }
}

我通常做的只是通过Redux连接底层组件。这有助于不从最顶层的组件中以大块的形式传递状态。

React 创作者之一 Dan Abramov 的精彩视频课程:Getting started with Redux

完全同意@t1gor。我们的答案是使用 REDUX。它为我们改变了整个游戏。突然嵌套 10 层深的按钮(即,在主视图内,header、header-container、左侧网格等,越来越深)到纯自定义组件中,有机会在需要时获取状态。

而不是...

  • Parent(向下传递状态)-拥有状态变量
    • Child(将再次传递)- parent 有状态变量
      • 孙子(将第三次传下去)- 孙子parent 有状态变量
        • 曾孙(需要那个状态变量)- 曾祖parent 有状态变量

你可以做到...

  • Parent(不通过)——读取全局状态变量
    • Child
      • 孙子
        • 曾孙 - 也读取相同的全局级别状态变量而不被传递...

通常代码看起来像这样...

'use strict'

//Importation of Connection Tools & View
import { connect } from 'react-redux';
import AppView from './AppView';


//Mapping -----------------------------------

const mapStateToProps = state => {
    return {
        someStateVar: state.something.capturedInState,
    };
}

const mapDispatchToProps = dispatch => {
    return {
        customFunctionsYouCreate: () => {
            //do something!
            //In your view component, access this by calling this.props.customFunctionsYouCreate
        },
    };
}

//Send Mappings to View...
export default connect(mapStateToProps, mapDispatchToProps)(AppView);

长话短说,您可以将所有全局应用程序状态级别的项目保存在称为商店的东西中,即使是最小的组件也需要来自应用程序状态的东西,它可以在构建视图而不是传递时获取它。

问题是内容如下,并且由于某种原因无法有效地保留未更改的子实例(无需重写整个 templateForChild)。

constructor (props) {
  super(props);

  // --- can't include refs --->
  // --- not subroutine of render --->
  this.state = {
    templateForChild: [
      <SomeComponentInstance className='hello' />,
      <AnotherComponentInstance className='world' />,
    ],
  };
}

componentDidMount () {
  this.setState({
    templateForChild: [ <div className='sometimes' /> ],
  }); // no refs for additional managing in this class
}

render () {
  return ( <OtherManagerComponent content={this.state.templateForChild} /> );
}
  1. 我相信答案可能是 include a ref callback function, rather than a string,正如 Dan Abramov 所提到的,尽管我还不确定 React 是否仍然会发出警告。这将确保为 CustomForm 和 BaseClass 分配相同的 ref 实例(当执行 props.ref 回调时)

  2. 答案可能是使用keycreateFragmentAn unrelated article that addresses a re-mounting problem。不确定该片段是否仍包含相同的实例,但文章确实是这样读的。这可能是 key 的目的,而不是 ref,后者是为了找到 DOM 节点(尽管 findDOMNode(ref) if !(ref instanceof HTMLElement).