Support for React Native ?
LyunKi opened this issue · 16 comments
I tried to use ayanami in RN but failed. Can ayanami support rn or is there any plan to adapt rn...
ayanami required TypeScript, could you provide tsconfig.json in your project?
{
"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 />;
}@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 sorry, the documents for latest versions is still in developing.
AddInjectableContextin youAppcomponent 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的依赖去掉后,程序确实运行成功了。下面会放上我的代码,麻烦能看一下
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>
);
}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.
@LyunKi ayanami@rc and @asuka/di is still in heavy developing. I will ensure this issue resolved when I finished develop.
@LyunKi
ayanami@rcand@asuka/diis 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 = . =
@LyunKi try 1.0.0-rc.5
@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;
- It seems that I have no need to add ? I tried to add it or remove it ,but with nothing changes
- the main entry port in expo is
"main": "node_modules/expo/AppEntry.js",it should be blamed for the failed DI?...
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 />;
}@LyunKi could you please upload a minimal repo to let me reproduce this bug?
@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..
@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
TLDR; just addplugins: ["babel-plugin-transform-typescript-metadata"]inbabel.config.js.The issue in your example is that expo use babel to precess TypeScript files, which won't follow tsconfig
--emitDecoratorMetadata trueto 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
