Skip to content
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

[DEV] hooks useTranslator and useSelector #1997

Closed
wants to merge 15 commits into from
Closed
16 changes: 16 additions & 0 deletions package-lock.json

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

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@
"timeout-signal": "^2.0.0",
"tmp": "^0.2.1",
"typed-redux-saga": "^1.5.0",
"use-sync-external-store": "^1.2.0",
"uuid": "^9.0.0",
"validator": "^13.11.0",
"xml-js": "^1.6.11",
Expand Down Expand Up @@ -334,6 +335,7 @@
"@types/remote-redux-devtools": "^0.5.5",
"@types/tmp": "^0.2.3",
"@types/urijs": "^1.19.19",
"@types/use-sync-external-store": "^0.0.4",
"@types/uuid": "^9.0.2",
"@types/validator": "^13.11.1",
"@types/xmldom": "^0.1.31",
Expand Down
20 changes: 20 additions & 0 deletions src/common/services/translator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,23 @@ export type I18nTyped = TFunction;
@injectable()
export class Translator {
public translate = this._translate as I18nTyped;
public subscribe = this._subscribe.bind(this);
private locale = "en";
private listeners: Set<() => void>;

constructor() {
this.listeners = new Set();
}

private _subscribe(fn: () => void) {
if (fn) {
this.listeners.add(fn);
return () => {
this.listeners.delete(fn);
};
}
return () => {};
}

public getLocale(): string {
return this.locale;
Expand All @@ -215,6 +231,10 @@ export class Translator {
} else {
resolve();
}
}).finally(() => {
for (const listener of this.listeners) {
listener();
}
});
}

Expand Down
28 changes: 28 additions & 0 deletions src/renderer/common/hooks/useApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as React from "react";
import { ReactReduxContext } from "react-redux";
import { v4 as uuidv4 } from "uuid";
import { TApiMethod, TApiMethodName } from "readium-desktop/common/api/api.type";
import { TModuleApi } from "readium-desktop/common/api/moduleApi.type";
import { TMethodApi } from "readium-desktop/common/api/methodApi.type";
import { apiActions } from "readium-desktop/common/redux/actions";
import { ApiResponse } from "readium-desktop/common/redux/states/api";
import { TReturnPromiseOrGeneratorType } from "readium-desktop/typings/api";

export function useApi<T extends TApiMethodName>(_requestId: string, apiPath: T, ...requestData: Parameters<TApiMethod[T]>): ApiResponse<TReturnPromiseOrGeneratorType<TApiMethod[T]>> {

const requestId = _requestId || React.useMemo(() => uuidv4(), []);
const { store } = React.useContext(ReactReduxContext);
React.useEffect(() => {
const splitPath = apiPath.split("/");
const moduleId = splitPath[0] as TModuleApi;
const methodId = splitPath[1] as TMethodApi;
store.dispatch(apiActions.request.build(requestId, moduleId, methodId, requestData));

return () => {
store.dispatch(apiActions.clean.build(requestId));
};
}, []); // componentDidMount

const apiResult = React.useSyncExternalStore(store.subscribe, () => store.getState().api[requestId]);
return apiResult;
};
10 changes: 10 additions & 0 deletions src/renderer/common/hooks/useDispatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as React from "react";
import { ReactReduxContext} from "react-redux";
import { Action } from "../../../common/models/redux";

export function useDispatch(action: Action) {

const {store} = React.useContext(ReactReduxContext);
const actionReturned = store.dispatch(action);
return actionReturned;
}
16 changes: 16 additions & 0 deletions src/renderer/common/hooks/useKeyboardShortcut.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as React from "react";
import { TKeyboardShortcutReadOnly } from "readium-desktop/common/keyboard";
import { registerKeyboardListener, unregisterKeyboardListener } from "../keyboard";
import { useSelector } from "./useSelector";
import { ICommonRootState } from "readium-desktop/common/redux/states/commonRootState";

export function useKeyboardShortcut(ListenForKeyUP: boolean, keyboardShortcut: (s: ICommonRootState["keyboard"]["shortcuts"]) => TKeyboardShortcutReadOnly, callback: () => void) {

const keyboardShortcutState = useSelector((state: ICommonRootState) => state.keyboard.shortcuts);
React.useEffect(() => {
registerKeyboardListener(ListenForKeyUP, keyboardShortcut(keyboardShortcutState), callback);
return () => unregisterKeyboardListener(callback);
}, [keyboardShortcutState]);

return ;
}
9 changes: 9 additions & 0 deletions src/renderer/common/hooks/useSelector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as React from "react";
import { ReactReduxContext, ReactReduxContextValue } from "react-redux";

export function useSelector<State, Selected>(selector: (state: State) => Selected): Selected {

const {store} = React.useContext<ReactReduxContextValue<State>>(ReactReduxContext);
const selected = React.useSyncExternalStore(store.subscribe, () => selector(store.getState()));
return selected;
}
19 changes: 19 additions & 0 deletions src/renderer/common/hooks/useTranslator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from "react";
import { Translator } from "readium-desktop/common/services/translator";
import { TranslatorContext } from "readium-desktop/renderer/common/translator.context";

export function useTranslator(): [typeof Translator.prototype.translate, Translator] {

const translator = React.useContext(TranslatorContext);
const { translate: __ } = translator;

const [, forceUpdate] = React.useReducer(x => x + 1, 0);
React.useEffect(() => {
const handleLocaleChange = () => {
forceUpdate();
};
return translator.subscribe(handleLocaleChange);
}, [translator.subscribe]);

return [__, translator];
}
78 changes: 78 additions & 0 deletions src/renderer/library/components/HooksTest.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import * as React from "react";
import { log } from "console";
import { ILibraryRootState } from "../redux/states";
import { useTranslator } from "readium-desktop/renderer/common/hooks/useTranslator";
import { useSelector } from "readium-desktop/renderer/common/hooks/useSelector";
import { useApi } from "readium-desktop/renderer/common/hooks/useApi";
// import { v4 as uuidv4 } from "uuid";
// import { TApiMethod, TApiMethodName } from "readium-desktop/common/api/api.type";
// import { ReactReduxContext} from 'react-redux'
// import { TModuleApi } from "readium-desktop/common/api/moduleApi.type";
// import { TMethodApi } from "readium-desktop/common/api/methodApi.type";
// import { apiActions } from "readium-desktop/common/redux/actions";
// import { useSyncExternalStore } from "readium-desktop/renderer/common/hooks/useSyncExternalStore";

export function HooksTest(props: { name: string }) {

const name = props.name;
// useSelector from react-redux
// const {locale} = useSelector((state: ILibraryRootState) => {

// log(Date.now().toString(), "useSelector Locale");
// return state.i18n;

// }
// ,
// (a, b) => {

// log("cond: ", a, b, a === b);
// return a === b
// }
// );

// const translator = React.useContext(TranslatorContext);
// const { translate: _ } = translator;
// // useSyncExternalStore(translator.subscribe, () => {console.log("a"); return translator.getLocale();});

// const [, forceUpdate] = React.useReducer(x => x + 1, 0);
// React.useEffect(() => {
// const handleLocaleChange = () => {
// forceUpdate();
// }
// return translator.subscribe(handleLocaleChange);
// }, [translator.subscribe]);
const [__] = useTranslator();
// let _ = (_a: any) => {};

// const {store} = React.useContext<ReactReduxContextValue<ILibraryRootState>>(ReactReduxContext);
// const id = useSyncExternalStore(store.subscribe, () => store.getState().win.identifier);
// log(id);

// useSelector custom with just useSyncExternalStore
const id = useSelector((state: ILibraryRootState) => state.win.identifier);
// let id = "";
log(id);

// const requestId = React.useMemo(() => uuidv4(), []);
const requestId: string = null;
log(requestId);
// useApi
// const [requestId] = React.useState('test');
// useDispatchApi(requestId, "publication/findAll");

// const { store } = React.useContext(ReactReduxContext);
// React.useEffect(() => {
// const apiPath = "publication/findAll";
// const requestData: any[] = [];
// const splitPath = apiPath.split("/");
// const moduleId = splitPath[0] as TModuleApi;
// const methodId = splitPath[1] as TMethodApi;
// store.dispatch(apiActions.request.build(requestId, moduleId, methodId, requestData))
// }, []);

// const allPubRes = useSyncExternalStore(store.subscribe, () => store.getState().api[requestId]);
const allPubRes = useApi(requestId, "publication/findAll");
log(allPubRes);
log(Date.now().toString(), "rendered");
return <h1 style={{ position: "absolute", top: 0, zIndex: 999 }}>Hello : {name} : id {id} : translate {__("header.books")}</h1>;
}
2 changes: 1 addition & 1 deletion src/renderer/library/components/SecondaryHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as stylesHeader from "readium-desktop/renderer/assets/styles/header.css
import { TranslatorProps, withTranslator } from "../../common/components/hoc/translator";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface IBaseProps extends TranslatorProps, React.PropsWithChildren {
interface IBaseProps extends TranslatorProps {
style?: React.CSSProperties;
id?: string;
}
Expand Down
Loading