我在弄清楚如何正确键入Redux 容器时遇到了一些麻烦。
考虑一个可能如下所示的简单展示组件:
interface MyProps {
name: string;
selected: boolean;
onSelect: (name: string) => void;
}
class MyComponent extends React.Component<MyProps, {}> { }
从这个组件的角度来看,所有的props都是必需的。
现在我想编写一个容器,将所有这些props拉出状态:
function mapStateToProps(state: MyState) {
return {
name: state.my.name,
selected: state.my.selected
};
}
function mapDispatchToProps(dispatch: IDispatch) {
return {
onSelect(name: string) {
dispatch(mySelectAction(name));
}
};
}
const MyContainer = connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
这是有效的,但有一个很大的类型问题:映射函数(mapStateToProps
和mapDispatchToProps
)没有保护它们提供正确的数据来实现MyProps
。这很容易出错、打字错误和重构不佳。
我可以使映射函数返回类型MyProps
:
function mapStateToProps(state: MyState): MyProps { }
function mapDispatchToProps(dispatch: IDispatch): MyProps { }
但是,除非我将所有MyProp
props 设为可选,否则这不起作用,以便每个映射函数只能返回它们关心的部分。我不想让 props 成为可选的,因为它们对于展示组件来说不是可选的。
另一种选择是拆分每个地图功能的props并将它们组合为组件props:
// MyComponent
interface MyStateProps {
name: string;
selected: boolean;
}
interface MyDispatchProps {
onSelect: (name: string) => void;
}
type MyProps = MyStateProps & MyDispatchProps;
class MyComponent extends React.Component<MyProps, {}> { }
// MyContainer
function mapStateToProps(state: MyState): MyStateProps { }
function mapDispatchToProps(dispatch: IDispatch): MyDispatchProps { }
好的,这让我更接近我想要的东西,但它有点嘈杂,它让我围绕容器的形状编写我的展示组件props界面,这是我不喜欢的。
现在出现了第二个问题。如果我想将容器放在另一个组件中怎么办:
<MyContainer />
这会导致name
、selected
和onSelect
都丢失的编译错误......但这是故意的,因为容器正在连接到 Redux 并提供这些。所以这促使我重新让所有组件 props 成为可选的,但我不喜欢那样,因为它们并不是真正的可选。
当MyContainer
有一些自己的 props 想要传入时,事情会变得更糟:
<MyContainer section="somethng" />
现在,我想要做的是有section
一个必需的propsMyContainer
,但不是一个propsMyComponent
,和name
,selected
以及onSelect
需要的propsMyComponent
,但可选的,或者不是在所有的propsMyContainer
。我完全不知道如何表达这一点。
对此的任何指导将不胜感激!