Skip to content

Support for React Native ? #116

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
LyunKi opened this issue Jan 6, 2020 · 16 comments
Closed

Support for React Native ? #116

LyunKi opened this issue Jan 6, 2020 · 16 comments
Assignees
Labels

Comments

@LyunKi
Copy link

LyunKi commented Jan 6, 2020

I tried to use ayanami in RN but failed. Can ayanami support rn or is there any plan to adapt rn...

@Brooooooklyn
Copy link
Contributor

ayanami required TypeScript, could you provide tsconfig.json in your project?

@LyunKi
Copy link
Author

LyunKi commented Jan 6, 2020

1D220F20-835B-462F-BE94-9039079E42D5

{
    "compilerOptions": {
        "allowSyntheticDefaultImports": true,
        "jsx": "react-native",
        "lib": ["dom", "es2015"],
        "moduleResolution": "node",
        "noEmit": true,
        "skipLibCheck": true,
        "resolveJsonModule": true,
        "baseUrl": ".",
        "paths": {
            "@/*": ["./src/*"]
        },
        "declaration": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "strict": true,
        "noUnusedParameters": true,
        "noUnusedLocals": true,
        "noImplicitAny": true,
        "noImplicitReturns": true,
        "module": "commonjs",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "target": "es5"
    }
}
import React, { useCallback } from 'react';
import { Ayanami, Effect, Reducer, useAyanami, useAyanamiState, Module } from 'ayanami';
import { of, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { View, Text, Button } from 'react-native';

interface State {
    count: number;
}

interface TipsState {
    tips: string;
}

@Module('Tips')
class Tips extends Ayanami<TipsState> {
    defaultState = {
        tips: '',
    };

    @Reducer()
    showTips(state: TipsState, tips: string): TipsState {
        return { ...state, tips };
    }
}

@Module('Count')
class Count extends Ayanami<State> {
    defaultState = {
        count: 0,
    };

    otherProps = ''

    constructor(private readonly tips: Tips) {
        super();
    }

    @Reducer()
    add(state: State, count: number): State {
        return { count: state.count + count };
    }

    @Reducer()
    addOne(state: State): State {
        return { count: state.count + 1 };
    }

    @Reducer()
    reset(): State {
        return { count: 0 };
    }

    @Effect()
    minus(count$: Observable<number>): any {
        return count$.pipe(
            mergeMap((subCount) =>
                of(
                    this.getActions().add(-subCount),
                    this.tips.getActions().showTips(`click minus Button at ${Date.now()}`)
                )
            )
        );
    }
}

function CountComponent() {
    const [{ count }, actions] = useAyanami(Count);
    const { tips } = useAyanamiState(Tips);

    const add = useCallback((count: number) => () => actions.add(count), []);
    const minus = useCallback((count: number) => () => actions.minus(count), []);
    const reset = useCallback(() => {
        actions.reset();
    }, []);

    return (
        <View>
            <Text>count: {count}</Text>
            <Text>tips: {tips}</Text>
            <Button title={'123'} onPress={add(1)}>
                add one
            </Button>
            <Button title={'234'} onPress={minus(1)}>
                minus one
            </Button>
            <Button title={'345'} onPress={reset}>
                reset to zero
            </Button>
        </View>
    );
}

export default function App() {
    return <CountComponent />;
}

@Brooooooklyn
Copy link
Contributor

Brooooooklyn commented Jan 6, 2020

@LyunKi sorry, the documents for latest versions is still in developing.
Add InjectableContext in you App component should fix your problem:

import { InjectableContext } from 'ayanami'


export default function App() {
    return <InjectableContext><CountComponent /></InjectableContext>;
}

@LyunKi
Copy link
Author

LyunKi commented Jan 6, 2020

@LyunKi sorry, the documents for latest versions is still in developing.
Add InjectableContext in you App component should fix your problem:

import { InjectableContext } from 'ayanami'


export default function App() {
    return <InjectableContext><CountComponent /></InjectableContext>;
}

我用中文表达吧 - 。 -应该更能传达意思,加了之后,di 还是失败了,提示 "cannot resolve all parameters for Count(?).xxxx".但我把 Count 对于 Tip的依赖去掉后,程序确实运行成功了。下面会放上我的代码,麻烦能看一下

@LyunKi
Copy link
Author

LyunKi commented Jan 6, 2020

import React, { useCallback } from 'react';
import {
    Ayanami,
    Effect,
    Reducer,
    useAyanami,
    useAyanamiState,
    Module,
    InjectableContext,
} from 'ayanami';
import { of, Observable } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { View, Text, Button } from 'react-native';

interface State {
    count: number;
}

interface TipsState {
    tips: string;
}

@Module('Tips')
class Tips extends Ayanami<TipsState> {
    defaultState = {
        tips: '',
    };

    @Reducer()
    showTips(state: TipsState, tips: string): TipsState {
        return { ...state, tips };
    }
}

@Module('Count')
class Count extends Ayanami<State> {
    defaultState = {
        count: 0,
    };

    otherProps = '';

    //将这一部分代码去掉后能运行成功
    constructor(private readonly tips: Tips) {
        super();
    }

    @Reducer()
    add(state: State, count: number): State {
        return { count: state.count + count };
    }

    @Reducer()
    addOne(state: State): State {
        return { count: state.count + 1 };
    }

    @Reducer()
    reset(): State {
        return { count: 0 };
    }

    @Effect()
    minus(count$: Observable<number>): any {
        return count$.pipe(
            mergeMap((subCount) =>
                of(
                    this.getActions().add(-subCount),
                    this.tips.getActions().showTips(`click minus Button at ${Date.now()}`)
                )
            )
        );
    }
}

function CountComponent() {
    const [{ count }, actions] = useAyanami(Count);
    const { tips } = useAyanamiState(Tips);

    const add = useCallback((count: number) => () => actions.add(count), []);
    const minus = useCallback((count: number) => () => actions.minus(count), []);
    const reset = useCallback(() => {
        actions.reset();
    }, []);

    return (
        <View>
            <Text>count: {count}</Text>
            <Text>tips: {tips}</Text>
            <Button title={'123'} onPress={add(1)}>
                add one
            </Button>
            <Button title={'234'} onPress={minus(1)}>
                minus one
            </Button>
            <Button title={'345'} onPress={reset}>
                reset to zero
            </Button>
        </View>
    );
}

export default function App() {
    return (
        <InjectableContext>
            <CountComponent />
        </InjectableContext>
    );
}

@LyunKi
Copy link
Author

LyunKi commented Jan 7, 2020

Cannot resolve all parameters for 'Count'(?). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Count' is decorated with Injectable.

@Brooooooklyn
Copy link
Contributor

@LyunKi ayanami@rc and @asuka/di is still in heavy developing. I will ensure this issue resolved when I finished develop.

@LyunKi
Copy link
Author

LyunKi commented Jan 7, 2020

@LyunKi ayanami@rc and @asuka/di is still in heavy developing. I will ensure this issue resolved when I finished develop.

thanks for your feedback,I think ayanami looks elegant and I hope to use it as my new state management tool for learning rxjs by the way = . =

@Brooooooklyn
Copy link
Contributor

@LyunKi try 1.0.0-rc.5

@LyunKi
Copy link
Author

LyunKi commented Jan 16, 2020

@LyunKi try 1.0.0-rc.5

thx,I'll try it

@LyunKi
Copy link
Author

LyunKi commented Jan 16, 2020

@LyunKi try 1.0.0-rc.5

emmm,when I tried it ,it could run as what I wish ,but when I triggered the minus function which would dispatch action in Tip modules,it crashed with error message

TypeError: undefined is not an object (evaluating '_this3.tips.getActions')

after reading the docs ,I felt confused with follows;

  1. It seems that I have no need to add ? I tried to add it or remove it ,but with nothing changes
  2. the main entry port in expo is "main": "node_modules/expo/AppEntry.js",it should be blamed for the failed DI?...

@LyunKi
Copy link
Author

LyunKi commented Jan 16, 2020

import 'reflect-metadata';

import {
    Ayanami,
    Effect,
    initDevtool,
    Module,
    Reducer,
    useAyanami,
    useAyanamiState,
} from 'ayanami';
import React, { useCallback } from 'react';
import { Button, Text, View } from 'react-native';
import { Observable, of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';

interface State {
    count: number;
}

interface TipsState {
    tips: string;
}

@Module('Tips')
class Tips extends Ayanami<TipsState> {
    defaultState = {
        tips: '123',
    };

    @Reducer()
    showTips(state: TipsState, tips: string): TipsState {
        return { ...state, tips };
    }
}

@Module('Count')
class Count extends Ayanami<State> {
    defaultState = {
        count: 0,
    };

    otherProps = '';

    constructor(private readonly tips: Tips) {
        super();
    }

    @Reducer()
    add(state: State, count: number): State {
        return { count: state.count + count };
    }

    @Reducer()
    addOne(state: State): State {
        return { count: state.count + 1 };
    }

    @Reducer()
    reset(): State {
        return { count: 0 };
    }

    @Effect()
    minus(count$: Observable<number>): any {
        return count$.pipe(
            mergeMap((subCount) =>
                of(
                    this.getActions().add(-subCount),
                    this.tips.getActions().showTips(`click minus Button at ${Date.now()}`)
                )
            )
        );
    }
}

function CountComponent() {
    const [{ count }, actions] = useAyanami(Count);
    const { tips } = useAyanamiState(Tips);

    const add = useCallback((count: number) => () => actions.add(count), [actions]);
    const minus = useCallback((count: number) => () => actions.minus(count), [actions]);
    const reset = useCallback(() => {
        actions.reset();
    }, [actions]);

    return (
        <View>
            <Text>count: {count}</Text>
            <Text>tips: {tips}</Text>
            <Button title={'123'} onPress={add(1)}>
                add one
            </Button>
            <Button title={'234'} onPress={minus(1)}>
                minus one
            </Button>
            <Button title={'345'} onPress={reset}>
                reset to zero
            </Button>
        </View>
    );
}

initDevtool();

export default function App() {
    return <CountComponent />;
}

@Brooooooklyn
Copy link
Contributor

@LyunKi could you please upload a minimal repo to let me reproduce this bug?

@LyunKi
Copy link
Author

LyunKi commented Jan 19, 2020

@LyunKi could you please upload a minimal repo to let me reproduce this bug?

as your wish~ https://github.com/LyunKi/example
could you please reopen this issue..

@forehalo
Copy link
Contributor

forehalo commented Jan 20, 2020

@LyunKi
TLDR; just add plugins: ["babel-plugin-transform-typescript-metadata"] in babel.config.js.

The issue in your example is that expo use babel to precess TypeScript files, which won't follow tsconfig --emitDecoratorMetadata true to emit parameters types required by DI.

For more information, please see:
babel/babel#9681
https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options

@LyunKi
Copy link
Author

LyunKi commented Jan 21, 2020

@LyunKi
TLDR; just add plugins: ["babel-plugin-transform-typescript-metadata"] in babel.config.js.

The issue in your example is that expo use babel to precess TypeScript files, which won't follow tsconfig --emitDecoratorMetadata true to emit parameters types required by DI.

For more information, please see:
babel/babel#9681
https://babeljs.io/docs/en/babel-plugin-transform-typescript#typescript-compiler-options

thx~I had tried your solution and the problem had been fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants