Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions .idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import React, {useState} from 'react';
import './App.css';
import {Chat} from "./chat/Chat";
import {StarredMessages} from "./starred-messages/StarredMessages";
import {Grid} from "@material-ui/core";
import {Button, Grid} from "@material-ui/core";
import {useUrlSearchParams} from "use-url-search-params";
import {UserLoader} from "./user-loader/UserLoader";

Expand All @@ -11,8 +11,9 @@ function randUser() {
}

function App() {
const [user] = useUrlSearchParams({userId: 0}, {userId: Number});
const userId: number = Number(user.userId);
// const [user] = useUrlSearchParams({userId: 0}, {userId: Number});
const [displayUserLoader, setDisplayUserLoader] = useState(true);
// const userId: number = Number(user.userId);
return (
<div>
{/*<Grid container spacing={3}>*/}
Expand All @@ -24,7 +25,8 @@ function App() {
{/* </Grid>*/}
{/*</Grid>*/}
<Grid>
<UserLoader />
<Button onClick = {_ => setDisplayUserLoader(!displayUserLoader)}>Toggle component</Button>
{displayUserLoader && <UserLoader />}
</Grid>
</div>
)
Expand Down
43 changes: 39 additions & 4 deletions src/Common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {Dispatch, Reducer, ReducerAction, useEffect} from "react";
import React, {Dispatch, Reducer, ReducerAction, useEffect, useRef} from "react";
import {fromEvent, merge, Observable} from "rxjs";
import {FromEventTarget} from "rxjs/internal/observable/fromEvent";

Expand All @@ -20,25 +20,60 @@ export const feedbackFactory: FeedbackFactory = <State>(state: State) => {
}
};

export function useFeedbackSet<State, Query>(
state: State,
query: (state: State) => Set<Query>,
effect: (query: Query) => Cleanup
) {
const activeEffects = useRef<Map<Query, Cleanup>>(new Map());

const newQueries = Array.from(query(state));
const currentQueries = Array.from(activeEffects.current.keys());
const queriesToDelete = currentQueries.filter(currentQuery => !newQueries.includes(currentQuery));
const queriesToAdd = newQueries.filter(newQuery => !currentQueries.includes(newQuery));

queriesToDelete.forEach(toDelete => {
const effectToDelete = activeEffects.current.get(toDelete) ?? unsupported("Effect must be present!");
effectToDelete(); // Run the cleanup function.
activeEffects.current.delete(toDelete);
});

queriesToAdd.forEach(toAdd => activeEffects.current.set(toAdd, effect(toAdd)))

// On unmount clear all the effects.
useEffect(() => {
return () => {
activeEffects.current.forEach(cleanUp => cleanUp());
activeEffects.current.clear();
};
}, [])
}

Comment on lines +23 to +51
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export const getDispatchContext = <State, Action>() => React.createContext(getIdDispatcher<State, Action>());

const getIdDispatcher: <State, Action>() => Dispatch<ReducerAction<Reducer<State, Action>>> = () => _ => {
throw Error("Using ID dispatcher!")
};

export const noop = () => {};
export const noop = () => {
};

export function unsupported(msg: string): never {
throw new Error(msg);
};

export function unsupportedAction<State, Action>(state: State, action: Action): never {
unsupported(`Cannot dispatch action ${JSON.stringify(action)} while state is ${JSON.stringify(state)}`);
}

// I initially wrote this as "Symbol("unit")" but this cannot be stringified with JSON.stringify.
export const Unit = {};

// export type TypeFromCreator<T extends { [key: string]: (...args: any) => object }> = ReturnType<T[keyof T]>;

export function assertNever(_: never): never { throw Error(); }
export function assertNever(_: never): never {
throw Error();
}

/**
* Rx helpers
Expand All @@ -60,7 +95,7 @@ export function useEventStream<Action, Query>(
) {
const deps = [JSON.stringify(query)];
useEffect(() => {
if(query === undefined) return;
if (query === undefined) return;
const subscription = merge(...events()).subscribe(action => dispatch(action));
return () => subscription.unsubscribe();
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
29 changes: 29 additions & 0 deletions src/rxjs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {Observable, Subject} from "rxjs";
import {publish, publishReplay, refCount} from "rxjs/operators";

test('RxJs', () => {

let state = 5;
const subject = new Observable(observer => {
// observer.next(state++);
observer.next(state);
observer.error("Greska")
// observer.complete();
}).pipe(
publish(),
refCount()
);

const getObserver = <T>(name: string) => ({
next: (n: T) => console.log(name + ": " + n),
error: (e: any) => console.log(name + ": " + e),
complete: () => console.log(name + ": " + 'Competed')
});


subject.subscribe(getObserver("A"));
subject.subscribe(getObserver("B"));
subject.subscribe(getObserver("C"));
});

export {}
13 changes: 6 additions & 7 deletions src/service/UserService.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import {User, UserId} from "../model/Model";
import Axios from "axios-observable";
import {map, publishReplay, refCount, retry, share, tap} from "rxjs/operators";
import {map, share, tap} from "rxjs/operators";
import {Observable, of} from "rxjs";
import {unsupported} from "../Common";
import LRU from "lru-cache";

interface UserService {
getUserWithId: (id: UserId) => Observable<User>
}

interface ValueAndRequest<Value> {
value?: Value
request: Observable<Value>
}

interface UserService {
getUserWithId: (id: UserId) => Observable<User>
}

class UserServiceImpl implements UserService {

private static readonly baseUrl = "http://localhost:5000/";
Expand All @@ -36,8 +36,7 @@ class UserServiceImpl implements UserService {
.pipe(
map(response => response.data),
tap(user => this.cacheUser(id, user)),
publishReplay(1),
refCount()
share(),
);
this.userCache.set(id, {
request: userRequest
Expand Down
1 change: 1 addition & 0 deletions src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';

Loading