是否可以创建为父组件提供配置的子节点?

时间:2015-10-23 21:32:39

标签: javascript reactjs react-jsx

我希望这样做的场景是创建一个通用的datagrid组件。我想使用子节点来定义网格的列,但我不希望这些子节点渲染,因为渲染逻辑被抽象为网格结构的呈现(下面的视图属性)

即,



<MyDataGrid data={myData} view={myTableView}>
  <MyCol fieldName='asdf' sortable />
</MyDataGrid>
&#13;
&#13;
&#13;

因为列为网格提供了渲染信息,所以它们需要在网格渲染功能中可访问,而无需先进行渲染。据我所知,这是不可能的,我目前只是将列配置作为网格上的道具传递。这种策略运作良好,但肯定不是最好看的策略。

我知道你可以构建可以使用的内在元素,但我认为React仍然希望将它们作为DOM节点进行管理。我想要的是反应忽略我组件的子节点的DOM,让我只是逐字解析子节点(即作为MyCol { fieldName: string, sortable: boolean }的数组。)

这可能吗?预定在路线图上?甚至考虑过?

我知道这是一个奇怪的问题,我很高兴继续我迄今为止采用的策略。但是可以选择创建这些无渲染的&#34; dumb &#34;节点

2 个答案:

答案 0 :(得分:1)

当然!请查看React Router以获取此配置样式的示例。也就是说,我认为它适用于嵌套的东西(如路线配置);否则,我建议只使用更多以JavaScript为中心的定义对象或对象数组的方式来配置网格。

在您的示例中,MyCol不需要呈现,您只想反省它创建的属性。这是一个例子:

var MyDataGrid  = React.createClass({
  render: function() {
    var options = React.Children.map(this.props.children, (child) => {
      return {
        type: child.type.displayName,
        sortable: !!child.props.sortable,
        fieldName: child.props.fieldName
      };
    });
    return <pre>{JSON.stringify(options, null, "  ")}</pre>
  }
});

var MyCol = React.createClass({
  render: function() {
    return null;
  }
});

var app = (
  <MyDataGrid>
    <MyCol fieldName='asdf' sortable />
    <MyCol fieldName='anotherColumn' />
  </MyDataGrid>
);

ReactDOM.render(app, document.getElementById("app"));

示例:https://jsbin.com/totusu/edit?js,output

答案 1 :(得分:0)

处理子元素进行配置的主要问题是,当您在父组件中收到子道具时,您的react组件类将不会调用它的构造函数。如果您有任何与需要应用的配置节点/组件关联的逻辑,这会使事情变得复杂。

我现在使用的模式如下(并确认按照您的预期工作)。我正在为组件使用ES6类,但该模式也适用于功能React.create*样式。

  1. 创建props接口(这定义了哪些道具可以在配置子节点中使用)
  2. 创建一个虚拟组件类,它使用您创建的道具(此组件实际上只是一个定义,不包含任何代码)
  3. 使用构造函数创建一个配置类,该构造函数使用所有道具并执行任何初始化逻辑。
  4. 向您的配置类添加一个静态create函数,该函数使用ReactElement并返回配置类的新实例(该元素将在jsx / tsx中定义道具
  5. 使用React.Children.map将子道具转换为父窗口中的配置实例数组(这可以在componentWillMount中完成并保存到实例变量中,除非您的列定义是可变的。)
  6. 简化示例(在Typescript中)

    interface IDataGridColumnProps {
      fieldName: string;
      header?: string;
      sortable?: boolean;
    }
    
    export class DataGridColumn extends React.Component<IDataGridColumnProps, any> {}
    
    class Column {
      constructor(public fieldName: string, public header?: string, public sortable = false) {
        if (this.header == null) {
          this.header = this.fieldName;
        }
      }
    
      public static create(element: React.ReactElement<IDataGridColumnProps>) {
        return new Column(element.props.fieldName, element.props.header, element.props.sortable);
      }
    }
    
    export class DataGridView /* ... */ {
      private columns: Column[];
    
      componentWillMount() {
        this.columns = React.Children.map(this.props.children, (x: React.ReactElement<IDataGridColumnProps>) => {
          return Column.create(x);
        });
      }
    }
    

    上面使用的模式实质上是将组件节点转换为父组件上的配置实例。原始子节点被抛出,它们提供的配置保留在父组件中的实例数组中。