2017-01-31 2 views
4

Ich habe die längste Zeit kämpfen mit diesem. Setzte sich heute Team widmet sich auf jeden any s links loszuwerden, aber nicht zu verwalten.Wie eine Art @connect richtig, wenn Reagieren und Typoskript mit?

import * as React from 'react'; 
import * as Redux from 'redux'; 
import { connect } from 'react-redux'; 
import { ReduxState } from './types'; 
import { syncItem, displayAlert } from './actionCreators'; 
import { SyncItemAction, DisplayAlertAction } from './actions'; 

// Props coming from Redux using `connect` and `mapStateToProps` 
type AppData = { 
    isSelected: boolean; 
    isInEditMode: boolean; 
}; 

// Action creators from `./actionCreators` all wrapped in `dispatch` using `connect` and `mapDispatchToProps` 
type AppActions = { 
    syncItem: (id: number) => SyncItemAction; 
    displayAlert: (text: string) => DisplayAlertAction; 
}; 

// Actual JSX attributes that will be required by the type system. 
type AppProps = { 
    id: number; 
    name: string; 
} & Partial<AppData> & Partial<AppActions>; // Making data and actions partial so that using <App /> in JSX doesn't yell. 

// The component's inner state. 
type AppState = Partial<{ 
    temp: string; 
}>; 

@connect<AppData, AppActions, AppProps>(mapStateToProps, mapDispatchToProps)(App) // Or mapDispatchToPropsAlt 
export default class App extends React.Component<AppProps, AppState> { 
    constructor(props: AppProps) { 
     super(props); 
    } 

    render() { 
     return (
      <div> 
       <h1>Hello, {this.props.name}! (#{this.props.id})</h1> 
       {/* In the below, syncItem should take the new name, a detail… Also ID could be provided in `mapStateToProps` by using `ownProps`! */} 
       Rename: <input value={this.state.temp} onChange={event => this.setState({ temp: event.target.value })} /> 
       <button onClick={_ => this.props.syncItem(this.props.id)}>Sync</button> 
      </div> 
     ); 
    } 
} 

function mapStateToProps(state: ReduxState, ownProps?: AppProps): AppData { 
    return { 
     isSelected: ownProps.id === state.selectedId, 
     isInEditMode: state.isInEditMode 
    }; 
} 

function mapDispatchToProps(dispatch: Redux.Dispatch<ReduxState>, ownProps?: AppProps): AppActions { 
    return { 
     syncItem: (id: number) => dispatch(syncItem(id)), 
     displayAlert: (text: string) => dispatch(displayAlert(text, ownProps.name)) 
    }; 
} 

function mapDispatchToPropsAlt(dispatch: Redux.Dispatch<ReduxState>, ownProps?: AppProps): AppActions { 
    return { 
     syncItem, 
     // Making this `null` because `displayAlert` above changes the signature by hiding the other parametr and taking it from `ownProps` - uncommon! 
     displayAlert: null 
    }; 
} 

function Test() { 
    // Only `id` and `name` is correctly required. 
    return <App id={0} name={'test'} />; 
} 

In dem obigen Code ich folgendes erhalten:

index.tsx(31,78): error TS2345: Argument of type 'typeof App' is not assignable to parameter of type 'ComponentClass<AppData & AppActions> | StatelessComponent<AppData & AppActions>'. 
    Type 'typeof App' is not assignable to type 'StatelessComponent<AppData & AppActions>'. 
    Type 'typeof App' provides no match for the signature '(props: AppData & AppActions & { children?: ReactNode; }, context?: any): ReactElement<any>' 

ich die Typdefinitionen mit in node_modules/@types zu kommen benutzt habe, was ich oben haben, und ich habe in ähnlicher Weise überprüft, was ComponentClass<T> aussieht . Es vorschlagen (es scheint mir), dass state der Komponente {} | void sein muss, was ich verstehe nicht, warum es der Fall ist, und auch wenn ich den Code oben ändern sagen <AppProps, void> oder <AppProps, {}> es nicht der erste Fehler in irgendeinem ändert Weg.

Wie soll ich vorgehen?

syncItem ist nur function syncItem(id: number): SyncItemAction und SyncItemActioninterface SyncItemAction extends Redux.Action { id: number; } ist, in ähnlicher Weise mit displayAlert.

Edit: Gefunden related question, aber dieser antwortet nicht, wie state kann auch eingegeben werden.

Antwort

1

Diese Antwort verwendet nicht die Anmerkung (und nutzt Schnittstellen statt Typen). Die Grundidee besteht darin, die Connected-Komponente und ihre Requisiten vollständig von der zugrunde liegenden Komponente zu trennen (typenweise).

Erstellen Sie eine Klasse ConnectedAppProps, die die Eigenschaften der angeschlossenen Komponente sind Sie an den Anbieter

interface ConnectedAppProps { 
    id: number; 
    name: string; 
} 

erweitern AppProps von dieser Schnittstelle

interface AppProps extends ConnectedAppProps, AppData, AppActions { 
} 

Erstellen Sie die ConnectedComponent

const ConnectedApp: React.ComponentClass<ConnectedAppProps> = 
    connect<AppData,AppActions,AppProps>(mapStateToProps, mapDispatchToProps)(App) 
aussetzen gehen

über die angeschlossene Komponente u nter die Provider mit seinem ConnectedAppProps

<Provider store={store}> 
     <ConnectedApp id={0} name={'test'} /> 
    </Provider> 

Verwenden mapStateToProp und mapDispatchToProps wie Sie heute Punkt zu „bereichern“, um die Komponente AppProps von denen der ConnectedAppProps

Verwandte Themen