Recently I wrote a business project, the existing code is MOBx + React Class, just want to use React Hook, so I made the following modifications to implement support

Code responsibility

  • Store is responsible for storing business data definitions
  • Action is responsible for manipulating data in the store
  • Component uses actions to manipulate data, uses Store data to display content, and state is responsible for UI interaction state

Existing code

Provider

import { Provider } from 'mobx-react';
export class ContainerProvider extends React.Component<any.any> {
    private injects: {
        [injectName: string]: any
    } = {};

    UNSAFE_componentWillMount() {
        const instances = injectInstance(
            assign({}, this.props.inject)
        );
        // Complex apps can do some initialization here
        this.injects = {};
        instances.forEach((value, key) = > {
            this.injects[key] = value;
        });
    }

    render() {
        return (
            <Provider {. this.injects} >
                {this.props.children}
            </Provider>); }}Copy the code

inject

export const injectDecorator = (injectName: string): any => (target: any, propertyKey: string, descriptor: PropertyDescriptor): any => { target[propertyKey] = injectName; // add an annotation variable if (! target['_injectVariables_']) { target['_injectVariables_'] = [propertyKey]; } else { target['_injectVariables_'].push(propertyKey); } return descriptor; }; export const injectInstance = (classes: {}) => { const classMap = new Map<string, any>(); const instanceMap = new Map<string, any>(); ForEach ((eachClassName) => {if (classmap. has(eachClassName)) {throw new Error(' duplicate className: ${eachClassName}`); } classMap.set(eachClassName, classes[eachClassName]); }); classMap.forEach((eachClass: any, keyName) => { instanceMap.set(keyName, new eachClass()); }); Instancemap. forEach((eachInstance: any, key: String) => {// Iterate over the injected class name eachInstance['_injectVariables_'] && eachInstance['_injectVariables_'].forEach((injectVariableKey: string) => { if (! instanceMap.get(eachInstance[injectVariableKey])) { throw new Error('injectName: ' + eachInstance[injectVariableKey] + ' not found! '); EachInstance [injectVariableKey] = instancemap. get(eachInstance[injectVariableKey]); }); delete eachInstance['_injectVariables_']; }); return instanceMap; };Copy the code

Store

export class DemoStore {
    @observable data={} 
}
Copy the code

Action

export class DemoAction {
	@inject('DemoStore') store: DemoStore;
    async getData() {
        this.store.data = await fetch(...);
    }
}
Copy the code

Component

interface Props { DemoStore? : DemoStore DemoAction? : DemoAction } @inject('DemoStore'.'DemoAction') 
@observer
export class Demo extends Component<Props.any> {
	render() {
        const { data } = this.props.DemoStore;
        return 
        <div onClick=(a)= >{this.props.DemoAction.getData()}>
        	{data}
        </div>}}Copy the code

The new code

Provider

export const StoreContext = createContext(null);
export const ContextProvider = observer((props: any) = > {
    const instances = injectInstance(
        assign({}, props.inject)
    );
    const injects = {};
    instances.forEach((value, key) = > {
        injects[key] = value;
    });
    return (
        <StoreContext.Provider value={injects}>
            {props.children}
        </StoreContext.Provider>
    );
});
Copy the code

useInject

export const useInject = (name) = > {
    const context = useContext(StoreContext);
    if (name && context) {
        return context[name];
    }
    return context;
};
Copy the code

Store

// Keep the same
Copy the code

Action

// Keep the same
@inject('DemoStore') store: DemoStore;
// If you can't get it, you can call it in init
// store: UCenterStore = useInject('DemoStore');
Copy the code

Component

import { useObserver } from 'mobx-react-lite';
export const Demo = memo((props: PropsDefine) = > {
    const action: DemoAction = useInject('DemoAction');
    const store: DemoStore = useInject('DemoStore');

	useEffect(() = >{ action.getData(); } []);const handleClick = useCallback((item, index) = > {
        // action.listItemClick(item, index);
        // action.log({
        // k: 'h5_click',
        // v: 'hot_words'
        // });} []);const { data } = store;
    return useObserver(() = > (
    	<div className='creater-page'>.</div>))}Copy the code

conclusion

The new Provider still instantiates and assigns objects by Inject, while the action&Store writing method remains unchanged. Hook is used in Component, action and Store instances are obtained by usrInject, and UI response to store is realized by useObserver