typescript + redux:在父组件中排除redux道具

Fel*_*iel 8 javascript typescript reactjs redux react-redux

我正在使用redux和typescript作为我当前的webapp.

定义组件的道具的最佳实践是什么,该组件通过@connect父级接收redux-actions ,但也来自父级?例:

// mychild.tsx
export namespace MyChildComponent {

  export interface IProps {
    propertyFromParent: string;
    propertyFromRedux: string;  // !!!! -> This is the problem
    actionsPropertyFromRedux: typeof MyReduxActions;  // !!!! -> And this     
  }
}

@connect(mapStateToProps, mapDispatchToProps)
export class MyChildComponent extends React.Component <MyChildComponent.IProps, any> {

... react stuff

}

function mapStateToProps(state: RootState) {
  return {
    propertyFromRedux: state.propertyFromRedux
  };
}
function mapDispatchToProps(dispatch) {
  return {
    actionsPropertyFromRedux: bindActionCreators(MyReduxActions as any, dispatch)
  };
}




// myparent.tsx
export class MyParentComponent extends React.Component <MyParentComponent.IProps, any> {

... react stuff

    render(){
        // typescript complains, because I am not passing `propertyFromRedux`! 
        return <div><MyChildComponent propertyFromParent="yay" /></div>;
    }

}
Run Code Online (Sandbox Code Playgroud)

我看到它有两个解决方案.

  1. 只需通过我的整个应用程序传递操作和状态.但这意味着即使只是一些小的子组件必须改变,我的整个应用程序也会被重新渲染.或者是在所有商店更改中收听我的顶级组件的redux方式?然后我必须在内部编写很多逻辑shouldComponentUpdate来制作没有扁平物体的道具.

  2. 设置帕拉姆中IPropsMyChildComponent 这样的可选:

-

// mychild.tsx
export namespace MyChildComponent {

  export interface IProps {
    propertyFromParent: string;
    propertyFromRedux?: typeof MyAction;  // This is the problem
  }
}
Run Code Online (Sandbox Code Playgroud)

还有另外一种方法吗?上述两种方式在我眼中看起来都太乱了.

Tyl*_*ian 19

您需要拆分你的道具-你需要一个DispatchProps,StatePropsOwnProps类型.你还必须使用TypeScript的泛型connect

  • DispatchProps 是你的行动创造者.
  • StateProps是你的状态道具(duh) - 这些来自mapStateToProps- 该函数的返回类型应该匹配此类型.
  • OwnProps是你的组件接受(也许是预期)的道具.可选的道具应在界面中标记为可选.

我这样做的方式(没有装饰器,但我相信它适用于此)是

interface ComponentDispatchProps {
    doSomeAction: typeof someAction;
}

interface ComponentStateProps {
    somethingFromState: any;
}

interface ComponentOwnProps {
    somethingWhichIsRequiredInProps: any;
    somethingWhichIsNotRequiredInProps?: any;
}

// not necessary to combine them into another type, but it cleans up the next line
type ComponentProps = ComponentStateProps & ComponentDispatchProps & ComponentOwnProps;

class Component extends React.Component<ComponentProps, {}> {...}

function mapStateToProps(state, props) { 
    return { somethingFromState };
}

export default connect<ComponentStateProps, ComponentDispatchProps, ComponentOwnProps>(
    mapStateToProps,
    mapDispatchToProps
)(Component);
Run Code Online (Sandbox Code Playgroud)

我认为你必须使用@connect<StateProps, DispatchProps, OwnProps>哪个将装饰并返回一个接受的类OwnProps.

如果你看一下connectTS 中的s实现

export declare function connect<TStateProps, TDispatchProps, TOwnProps>(...): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>

interface ComponentDecorator<TOriginalProps, TOwnProps> {
    (component: ComponentClass<TOriginalProps> | StatelessComponent<TOriginalProps>): ComponentClass<TOwnProps>;
}
Run Code Online (Sandbox Code Playgroud)

connect<...>返回一个ComponentDecorator,当传递组件时(在你的情况下,这是在转发装饰器时透明地完成),无论如何StateProps,并DispatchProps返回一个期望的组件OwnProps.

connect (非泛型)返回 InferableComponentDecorator

export interface InferableComponentDecorator {
    <P, TComponentConstruct extends (ComponentClass<P> | StatelessComponent<P>)>(component: TComponentConstruct): TComponentConstruct;
}
Run Code Online (Sandbox Code Playgroud)

它试图根据提供给组件的道具来推断道具,在你的情况下是所有道具的组合(从上面OwnProps变成ComponentProps).

  • 不知道为什么这个解决方案对我来说不成功——这是什么类型的版本和 react-redux 版本? (2认同)