问题
I'm converting a react project from redux to mobx, and I'm having the following problem: I was using the container/presenter pattern with redux, which meant using the redux "connect" function, like this:
export default connect(mapStateToProps, mapDispatchToProps)(Leads);
The problem I'm having is that there's no equivalent mobx function, so instead, I tried to simply create an instance of the component in the container. Something like:
render() {
return (
<MyComponent
store={mystore}
/>
);
}
Unfortunately, that doesn't work, because MyComponent has injected properties from react-router, something like this:
class MyComponent extends React.Component<ReportProps & RouteComponentProps<ReportProps>> {
constructor(public routeProps: ReportProps & RouteComponentProps<ReportProps>) {
super(routeProps);
}...
I tried getting rid of the container concept, but the same problem occurs in other places because I'm using the mobx-react @inject decorator. For example, I have a component like this:
export interface AddressProps {
report: IReportStore;
}
@inject((rootStore: RootStore) => ({
report: rootStore.report
}))
@observer
class Address extends React.Component<AddressProps> {
...
If I then try to use my component somewhere, typescript complains that I'm not passing the required property (report, in this instance), even though I shouldn't need to, since I'm injecting the properties.
I figure I must be missing something basic, as this is a fairly straightforward use of mobx. Or maybe it's just a typescript problem...? If so, any ideas how to fix or work around it?
Thanks in advance, Jonathan
回答1:
There are a lot of problems around the mobx inject method.
the original idea was to return a Partial<TProps>
but you can't do this typed without losing your original Class: React.Component<Partial<TProps>,TState>
!= YourComponent
- the set properties.
Read the discussed problem here: https://github.com/mobxjs/mobx-react/issues/256
Simplistic solution
Use optional parameters in props and set them in a getter property:
interface AppProps {
store?: SDtore;
}
class App {
get store(): TimeEntryStore {
return this.props.store as Store;
}
method(){
this.store;///
}
}
Other solution
If you want to keep your required parameters (eg: for using the component outside of mobx etc).
You can consider casting the component to React.Component<TPropsReduced,State>
where TPropsReduced is a self defined interface with required props after injected.
The downsides are:
- Losing type safety at casting (eg if you make mistakes/typo's in the interface properties. (can be solved by extending/subclassing interfaces.
- Losing methods calls. You will no longer have typed methods on the component (eg: when you use
ref={()=>}
), but using this is dis-advised anyways.
Example:
interface AddressPropsMobx {
}
interface AddressProps extends AddressPropsMobx {
report: IReportStore;
}
//Pure react component
class Address extends React.Component<AddressProps> {}
// Mobx version:
const MobxAddress = inject((rootStore: RootStore) => ({
report: rootStore.report
}))(observer(Address)) as React.Component<AddressPropsMobx>; //unsafe cast
来源:https://stackoverflow.com/questions/50318437/how-to-instantiate-react-component-with-injected-properties