首页 文章

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

提问于
浏览
6

我正在使用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>;
    }

}

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

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

  • IProps 中的参数设置为 MyChildComponent 可选,如下所示:

// mychild.tsx
export namespace MyChildComponent {

  export interface IProps {
    propertyFromParent: string;
    propertyFromRedux?: typeof MyAction;  // This is the problem
  }
}

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

1 回答

  • 17

    你需要拆分你的道具 - 你需要 DispatchPropsStatePropsOwnProps 类型 . 你'll also have to use 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);
    

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

    如果你看一下TS中的 connect 实现

    export declare function connect<TStateProps, TDispatchProps, TOwnProps>(...): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>
    
    interface ComponentDecorator<TOriginalProps, TOwnProps> {
        (component: ComponentClass<TOriginalProps> | StatelessComponent<TOriginalProps>): ComponentClass<TOwnProps>;
    }
    

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

    connect (非泛型)返回 InferableComponentDecorator

    export interface InferableComponentDecorator {
        <P, TComponentConstruct extends (ComponentClass<P> | StatelessComponent<P>)>(component: TComponentConstruct): TComponentConstruct;
    }
    

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

相关问题