typeless-js / typeless Goto Github PK
View Code? Open in Web Editor NEWA complete toolkit for building scalable React apps with Typescript.
Home Page: https://typeless.js.org
License: MIT License
A complete toolkit for building scalable React apps with Typescript.
Home Page: https://typeless.js.org
License: MIT License
I want to apply middleware for error tracking using Sentry.
When using Sentry, I want to log dispatched Actions to Sentry's Breadcrumb and get application state at the time error occurred.
Now, I think how to implement middleware like behavior is following example.
But, it is difficult to get all of store's state...
class MyRegistry extends Registry {
dispatch(action: ActionLike) {
// some implementation of correspond to middleware
// ...
super.dispatch(action);
}
}
The tsconfig.json in the "Counter" example have an error.
https://typeless.js.org/introduction/examples
I accessed "Live demo" link, but "Browser" tab does not display correct content.
https://codesandbox.io/s/h84n1
Error
We weren't able to parse: '/tsconfig.json': Parse error on line 4:
...aultImports": true, // no errors on comm
-----------------------^
Expecting 'STRING', got 'undefined'
After receiving feedback from other developers, I decided to make the following design changes:
immer
. Peer dependecies are still React
and RxJS
.Example counter app.
import React from 'react';
import ReactDOM from 'react-dom';
import * as Rx from 'typeless/rx';
import { createModule, useActions } from 'typeless';
/* == Module Interface == */
export const [useModule, CounterActions, getCounterState] = createModule(
Symbol('counter')
)
// Create Actions Creators
.withActions({
startCount: null, // null means no args
countDone: (count: number) => ({ payload: { count } }),
})
.withState<CounterState>();
export interface CounterState {
isLoading: boolean;
count: number;
}
/* == Module Implementation == */
const initialState: CounterState = {
isLoading: false,
count: 0,
};
// Create Epic for side effects
useModule
.epic()
// Listen for `count` and dispatch `countDone` with 500ms delay
.on(CounterActions.startCount, () =>
Rx.of(CounterActions.countDone(1)).pipe(Rx.delay(500))
);
// Create a reducer
// Under the hood it uses `immer` and state mutations are allowed
useModule
.reducer(initialState)
.on(CounterActions.startCount, state => {
state.isLoading = true;
})
.on(CounterActions.countDone, (state, { count }) => {
state.isLoading = false;
state.count += count;
});
/* == Use Module in React == */
export function Counter() {
// load epic and reducer
useModule();
// wrap actions with `dispatch`
const { startCount } = useActions(CounterActions);
// get state from store
const { isLoading, count } = getCounterState.useState();
return (
<div>
<button disabled={isLoading} onClick={startCount}>
{isLoading ? 'loading...' : 'increase'}
</button>
<div>count: {count}</div>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('app'));
Example of using multiple modules in React components:
function App() {
useXModule();
useYModule();
const { countX, countY } = useMappedState(
[getXState, getYState],
(xState, yState) => ({
countX: xState.count,
countY: yState.count,
})
);
return <div>...</div>
}
Added createDeps
to avoid duplicated code with useMappedState
const deps = createDeps({ x: getXState, y: getYState });
function App() {
useXModule();
useYModule();
const { countX, countY } = deps.useMappedState(
(state) => ({
countX: state.x.count,
countY: state.y.count,
})
);
return <div>...</div>
}
When the same typeless module
is used by multiple React Component
, in the following procedure $unmonting ($unmounted)
dispatched after $mount
.
At this time, reducer
and epic
will be unregistered.
typeless module
(created by typeless's createModule
API) in a React Component
React Component
which uses the same typeless module
(unmount and mount must be triggered at the same rendering step)$unmounting
and $unmounted
are dispatched after $mounted
action.http://localhost:3000
toggle state
show foo
Then, Foo/SHOW_FOO
action is dispatched, but epic won't be executed.
In this case, run FooAction.showFoo
epic normaly.
typeless: 0.1.9-alpha.0
, 0.2.0
react: ^16.8.4
I think CI result should be displayed PR checks, but not exists in the lists( ref. #67 )
And Codcov notification doesn't exist on PR comment
Why is it?
I want to enforce deps
like a react-hooks/exhaustive-deps
.
But react-hooks/exhaustive-deps
has no custom rule for external API.
EpicResult
to assign Promise<ActionLike>
TypelessActions.ignore()
EpicResult
to assign Promise<ActionLike>
async/await is sometimes useful.
Following example, make an Action with getSomeId
's result and getSomebodyById
's result using Observable
pattern and Promise
pattern
.epic()
// using Observable
.on(SomeActions.fetchSomebody, () => {
return Rx.from(API.getSomeId()).pipe(
Rx.mergeMap(id =>
Rx.from(API.getSomebodyById(id)).pipe(
Rx.map(somebody => SomeActions.fetchSomebodyFulfilled({ id, somebody })),
),
),
Rx.catchError(e => Rx.of(SomeActions.rejected())),
);
})
// using Promise
.on(SomeActions.fetchSomebody, async () => {
try {
const id = await API.getSomeId();
const somebody = await API.getSomebodyById(id);
return SomeActions.fetchSomebodyFulfilled({ id, somebody });
} catch (e) {
return SomeActions.rejected();
}
});
Nested Observable
is too complex.
So, I want to use Promise
like in this case.
TypelessActions.ignore()
It is difficult to ignore EpicHandler
which returns Promise
.
So, create built-in ignore
Action.
.on(SomeActions.fetchSomebody, async () => {
// this result type is `Promise<Observable<>>`, so this is not work!
return Rx.empty();
})
.on(SomeActions.fetchSomebody, async () => {
// this result type is Promise<ActionLike>, and works well!
return TypelessActions.ignore();
})
When returned TypelessActions.ignore()
, it is converted Rx.empty()
in createOutputStream
.
I think this feature request may breaks typeless concept.
So, If you say this is not for typeless, I'll certainly withdraw this request.
Thank you.
I think automatically deployment should run only when master branch is updated.
But now, deployment runs when a pull request is created/updated.
typeless
has complex type inference, but has no test for types.
This causes that to fix and verify types is difficulty (e.g. #30).
So, I think typeless
need to add type testing.
This approach is very simple and no dependency.
Testing type is done all of tsc
Need to make all of assert functions and test structure helpers.
Developer maybe to have pain if more complex testing.
Using tsd
createDeps
has no documentation.
So, I wonder it is stable API.
I think it needs following work.
Now, typeless 0.1.9-alpha.0
version published as latest at npm.
So, run npm install typeless
, then installed 0.1.9-alhpa-0
version.
0.1.9-alpha.0
is developing now, and different from document
This causes counfusing for users, so I think to publish with beta tag.
useMappedState
execute force re-render when Store
's subscription emitted.
When a Component depends on typeless module's state, performance tuning more difficulty by this behavior.
It shouldn't execute force re-render when useMappedState
's result got same value.
react-redux's useSelector
and reselect's createSelector
are solved this problem.
Following example, I made comparison of typeless and react-redux/reselect.
code sandbox
@lstkz I'll make PR if you don't mind.
Currently, we keep the whole state in the store, and very often it causes performance issues.
We could implement something similar to Formik, where we keep the state locally, and when the form is submitted successfully, we dispatch an action with the form values.
If someone is interested in implementing it, we can discuss the API here.
The stream created by Epic#toStream catches error on catchError
operator.
This makes to capture error impossible.
I want to track error occurred Epic, but it is difficult.
I tried to remove catchError
in this line
And run following example code
Then, it is captured.
epic().on(SomeActions.occurredError, () => {
// This error is not captured window.addEventListener("error").
throw new Error('some error');
return null;
});
Idea 1. Call window.dispatchEvent
in catchError
operator.
Idea 2. Enable to register error callback function that called in catchError
operator.
How about these ideas, which is better you think?
RxJS solves this problem.
https://github.com/ReactiveX/rxjs/blob/master/src/internal/util/hostReportError.ts#L6-L8
I think this is best way, I'll submit PR.
In many case, computed value from State
is used in Component and typeless Module.
To do that, declare computing function in a file, and import the function from file when use at Component or Module.
Some might directly use state values even though a computing function is already declared
So, I want API that allows to declare computing function
Add .withComputed(computed: {[key:string]: (state: TState) => any})
function in createModule().withState()
's returned value.
.withComputed
function allows to add computing functions map.
.withComputed
returns ComputedStateGetter
function that returns state
and computed
property.
The state
is a Store's state, computed
is an object has computed values which used computing function declared withComputed
function's arguments.
// interface.ts
const [handle, getState] = createModule(symbol)
.withState<UserState>()
.withComputed({ existsUser: state => state.user !== null })
interface UserState { user: string | null; }
// module.tsx
handle.redcer({user:null})
const UserModule = ()=>{
handle()
const { state, computed } = getState.useState();
console.log(state.user, computed.existsUser); // => null, false
return null;
}
PoC implementation: sisisin@9916ada#diff-7e4c6d666ceff158a5cf87a39e477085R104-R120
.withActions
functionStateGetter
changes only when.withComputed
is calledStateGetter
. StateGetter
returns TState
type, but ComputedStateGetter
returns {state: TState}
.ComputedStateGetter
returns nested object because works well a case of primitive value State
getState(): TState & Computed
easy-peasy's computed API: https://easy-peasy.now.sh/docs/api/computed.html
yarn start
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.