无论出于何种原因,我根本无法让 Waiski 的答案为我工作。我假设过去两年里 Griddle 一定发生了一些变化。看起来目前网络上流行的建议是“将行选择作为插件实现”,但我也找不到任何例子。在对 GitHub 上Position 插件的 TableEnhancer的代码进行了长时间的仔细研究之后,经过大量的反复试验,我最终设法在 TypeScript 中拼凑了以下用于 Griddle 的行选择插件:
import * as React from "react";
import * as Redux from "redux";
import Griddle, { connect, GriddlePlugin, components } from "griddle-react";
export type RowId = string | number;
export type RowClickHandler = (event: React.MouseEvent<Element>, rowId: RowId) => void;
export type RowIdGetter<TData> = (rowData: TData) => RowId;
export interface IRowEnhancerProps {
rowClickHandler: RowClickHandler;
rowId: RowId;
isSelected: boolean;
}
export class RowSelector<TData> {
private _rowClickHandler: RowClickHandler = null;
private _rowIdGetter: RowIdGetter<TData>;
constructor(rowClickHandler: RowClickHandler, rowIdGetter: (rowData: TData) => RowId) {
this._rowClickHandler = rowClickHandler;
this._rowIdGetter = rowIdGetter;
}
public rowIdToSelect: RowId;
public plugin: GriddlePlugin = {
components: {
RowEnhancer: (OriginalComponent: React.ComponentClass<components.RowProps>) =>
this.rowSelectionEnhancer(OriginalComponent)
}
}
private rowSelectionEnhancer(
OriginalComponent: React.ComponentClass<components.RowProps>
): React.ComponentClass<components.RowProps> {
const rowDataSelector = (state, { griddleKey }) => {
return state
.get('data')
.find(rowMap => rowMap.get('griddleKey') === griddleKey)
.toJSON();
};
return Redux.compose(
connect((state, props) => {
const rowData: TData = rowDataSelector(state, props as { griddleKey });
const rowId: RowId = this._rowIdGetter(rowData);
return {
...props,
rowClickHandler: this._rowClickHandler,
rowId: rowId,
isSelected: rowId.toString() === this.rowIdToSelect.toString()
};
})
)(class extends React.Component<IRowEnhancerProps, any>{
public render() {
return (
<OriginalComponent
{...this.props}
onClick={(event) => this.props.rowClickHandler(event, this.props.rowId)}
className={this.props.isSelected ? "selected" : ""}
/>
);
}
});
}
}
这是组件如何使用它的粗略概述。(请注意,我必须从更大、更复杂的组件中选择性地提取此示例,因此可能存在一些错误/不一致;对此感到抱歉。它仍然应该对方法有一个很好的总体了解。)
import * as React from "react";
import Griddle, { RowDefinition, plugins, GriddlePlugin} from "griddle-react";
import * as MyGriddlePlugins from "../GriddlePlugins";
export interface IPartInfo {
serialNumber: number,
name: string,
location: string
}
export interface IPartListProps{
parts: IPartInfo[],
selectedSerialNumber: number
}
export class PartList extends React.Component<IPartListProps, void > {
private rowSelector: MyGriddlePlugins.RowSelector<IPartInfo>;
private rowIdGetter: MyGriddlePlugins.RowIdGetter<IPartInfo>;
constructor(props?: IPartListProps, context?: any) {
super(props, context);
this._rowClickHandler = this._rowClickHandler.bind(this);
this.rowSelector = new MyGriddlePlugins.RowSelector(
this._rowClickHandler,
this._rowIdGetter);
}
private _rowClickHandler: MyGriddlePlugins.RowClickHandler =
(event: React.MouseEvent<Element>, selectedSerialNumber: MyGriddlePlugins.RowId) => {
if (selectedSerialNumber !== this.props.selectedSerialNumber) {
/*
Set state, dispatch an action, do whatever. The main point is that you
now have the actual event from the click on the row and the id value from
your data in a function on your component. If you can trigger another
render pass from here and set a fresh value for this.rowSelector.rowIdToSelect
then the "selected" CSS class will be applied to whatever row this click
event just came form so you can style it however you like.
*/
}
}
private _rowIdGetter: (rowData: IPartInfo) => MyGriddlePlugins.RowId =
(rowData: IPartInfo) => rowData.serialNumber;
public render(): JSX.Element {
this.rowSelector.rowIdToSelect = this.props.selectedSerialNumber;
return (
<div>
<Griddle
data={this.props.parts}
plugins={[plugins.LocalPlugin, this.rowSelector.plugin]}
>
<RowDefinition>
<ColumnDefinition id="name" title="Part Name" />
<ColumnDefinition id="location" title="Installed Location" />
<ColumnDefinition id="serailNumber" title="Serial Number" />
</RowDefinition>
</Griddle>
</div>
);
}
}
那么,这里到底发生了什么?该组件在实例化时创建插件类的实例,传入事件处理程序以捕获对行的点击和访问器函数以从数据行中检索您的 ID 值(不是难以理解的内部 ID)。就在组件返回其渲染之前,在组件的插件实例上设置一个值,这样,当 Griddle 渲染插件时,插件就有数据来确定它何时在选定的行上,然后相应地调整 CSS。然后将组件中的处理程序函数分配给该行的 onClick 处理程序,以便您的组件可以从单击中获取数据并执行它需要执行的任何操作。
这通过了“它对我有用”测试(在 React 15.6 上),在我的例子中,这是一个由通过 Griddle 实现的传统表格驱动的简单的主/详细视图。我不知道它与 Griddle 的一些更高级的功能配合得如何。