反応コンポーネントのパラメーターを入力しようとするとエラーが発生します。プロパティのプロパティとコンポーネントの状態をstronlyで入力したいのですが、Reduxを使用してそうすると、mapStateToPropsを接続関数に渡すとエラーが発生します。
これはコンポーネントコードです。
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import FileExplorer from '../components/file-Explorer/file-Explorer';
import { ISideMenu, ISideMenuState } from '../models/interfaces/side-menu';
class SideMenu extends Component<ISideMenu, ISideMenuState> {
render() {
return (
<div>
{this.props.fileExplorerInfo !== null &&
<FileExplorer fileExplorerDirectory={this.props.fileExplorerInfo.fileExplorerDirectory}/>
}
</div>
);
}
}
const mapStateToProps = (state: ISideMenuState) => {
return {
fileExplorerInfo: state.fileExplorer
};
};
export default connect<ISideMenu, null, ISideMenuState>(mapStateToProps)(SideMenu);
そのため、次の行でエラーが発生します。
export default connect<ISideMenu, null, ISideMenuState>(mapStateToProps)(SideMenu);
そして、その行の「mapStateToProps」という単語にカーソルを合わせると、エラーが表示されます。
Argument of type '(state: ISideMenuState) => { fileExplorerInfo: FileDirectoryTree | null; }'
is not assignable to parameter of type 'MapStateToPropsParam<ISideMenu, ISideMenuState, {}>'.
Type '(state: ISideMenuState) => { fileExplorerInfo: FileDirectoryTree | null; }' is not
assignable to type 'MapStateToProps<ISideMenu, ISideMenuState, {}>'.
Types of parameters 'state' and 'state' are incompatible.
Type '{}' is not
assignable to type 'ISideMenuState'.
Property 'fileExplorer' is missing in type '{}'.
そして、これらは私が反応コンポーネントで使用している2つのインターフェースです:
export interface ISideMenu {
fileExplorerInfo: FileExplorerReducerState | null;
}
export interface ISideMenuState {
fileExplorer: FileDirectoryTree | null;
}
このエラーについての洞察は大歓迎です!
ジェネリックを使用する場合、インターフェイスの場所が間違っています:
React component:を宣言するとき
_class Comp extends Component<ICompProps, ICompState>
_
ICompProps
とICompState
は、それぞれコンポーネントの小道具と内部状態です。
connectを使用する場合:
_connect<IMapStateToProps, IMapDispatchToProps, ICompProps, IReduxState>
_
IMapStateToProps
は、mapStateToProps()
関数によって返されるものを表します。 IMapDispatchToProps
は、mapDispatchToProps()
関数によって返されるものを表します。 ICompProps
は、Reactコンポーネントの小道具(上記と同じ)を表します)IReduxState
は、アプリのRedux状態を表します
つまり、特定の例では:
Reactコンポーネント:
_class SideMenu extends Component<ISideMenu, {}>
_
状態を使用しないので、小道具にはISideMenu
を使用し、状態には_{}
_(空の状態)を使用します。
接続を使用する場合:
_connect<ISideMenu, {}, ISideMenu, ISideMenuState>(mapStateToProps)(SideMenu);
_
ISideMenu
をReactコンポーネントの小道具とmapStateToProps
によって返されるオブジェクトの両方として使用できます。しかし、実際には2つの個別のインターフェースを作成するのが最善です。
私のアプリでは、通常、mapStateToProps
戻りオブジェクトを入力するのが面倒なので、次のように使用します。
_connect<{}, {}, ISideMenu, ISideMenuState>(mapStateToProps)(SideMenu);
_
上記のコードからいくつかのアンチパターンを削除してもかまわないことを願っています。追加したコメントを確認してください。また、パターンをより良く示すためにwithRouterを追加しました
import * as React from "react";
import { bindActionCreators } from "redux";
import { withRouter, RouteComponentProps } from "react-router";
import { connect } from "react-redux";
import { compose } from "recompose";
// OUR ROOT REDUX STORE STATE TYPE
import { State } from "../redux";
import FileExplorer from "../components/file-Explorer/file-Explorer";
// interfaces starting with 'I' is an antipattern and really
// rarely needed to be in a separate file
// OwnProps - that's what external code knows about out container
type OwnProps = {};
// this comes from redux
type StateProps = {
fileExplorer: FileDirectoryTree | null;
};
// resulting props - that what container expects to have
type Props = OwnProps & StateProps & RouteComponentProps<any>;
// no need to have a class, SFC will do the same job
const SideMenu: React.SFC<Props> = props => {
return (
<div>
{this.props.fileExplorerInfo !== null && (
<FileExplorer
fileExplorerDirectory={
this.props.fileExplorerInfo.fileExplorerDirectory
}
/>
)}
</div>
);
};
// compose (from recompose lib) because usually we have more than 1 hoc
// say let's add withRouter just for fun
export default compose<Props, OwnProps>(
withRouter,
// it's important to read the typings:
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-redux/index.d.ts
connect<StateProps, {}, {}, State>(s => ({
fileExplorerInfo: s.fileExplorer
})),
)(SideMenu);