【发布时间】:2018-07-20 18:14:37
【问题描述】:
使用 React 的新上下文 API,您可以像这样创建类型化的上下文生产者/消费者:
type MyContextType = string;
const { Consumer, Producer } = React.createContext<MyContextType>('foo');
但是,假设我有一个列出项目的通用组件。
// To be referenced later
interface IContext<ItemType> {
items: ItemType[];
}
interface IProps<ItemType> {
items: ItemType[];
}
class MyList<ItemType> extends React.Component<IProps<ItemType>> {
public render() {
return items.map(i => <p key={i.id}>{i.text}</p>);
}
}
如果我想将一些自定义组件呈现为列表项并将MyList 中的属性作为上下文传递,我将如何实现呢?有没有可能?
我尝试过的:
方法#1
class MyList<ItemType> extends React.Component<IProps<ItemType>> {
// The next line is an error.
public static context = React.createContext<IContext<ItemType>>({
items: []
}
}
这种方法不起作用,因为您无法从静态上下文中访问类的类型,这是有道理的。
方法#2
使用标准上下文模式,我们在模块级别(即不在类内部)创建消费者和生产者。这里的问题是我们必须在知道它们的类型参数之前创建消费者和生产者。
方法#3
我发现 a post on Medium 反映了我正在尝试做的事情。交换的关键是在我们知道类型信息之前我们不能创建生产者/消费者(看起来很明显对吧?)。这导致了以下方法。
class MyList<ItemType> extends React.Component<IProps<ItemType>> {
private localContext: React.Context<IContext<ItemType>>;
constructor(props?: IProps<ItemType>) {
super(props);
this.localContext = React.createContext<IContext<ItemType>>({
items: [],
});
}
public render() {
return (
<this.localContext.Provider>
{this.props.children}
</this.localContext.Provider>
);
}
}
这是(也许)进步,因为我们可以实例化正确类型的提供者,但是子组件如何访问正确的消费者?
更新
正如下面的答案所提到的,这种模式是试图过度抽象的标志,这在 React 中效果不佳。如果要尝试解决这个问题,我会创建一个通用的ListItem 类来封装项目本身。这样,上下文对象可以输入任何形式的ListItem,我们不必动态创建消费者和提供者。
【问题讨论】:
标签: reactjs typescript