Skip to content

Commit

Permalink
refactor: do not use hook on client to run logic
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeysova committed Jan 24, 2021
1 parent 55f3031 commit 813df4c
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 137 deletions.
6 changes: 4 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
{
"importName": "lib/page-routing",
"eventCreators": ["createStart"],
"noDefaults": true
"noDefaults": true,
"addLoc": true
},
"page-routing"
],
[
"effector/babel-plugin",
{
"importName": "effector-root",
"noDefaults": true
"noDefaults": true,
"addLoc": true
},
"effector-root"
]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"effector": "^21.7.5",
"effector-inspector": "^0.4.1",
"effector-logger": "^0.9.0",
"effector-react": "^21.2.0",
"effector-react": "^21.2.1",
"effector-reflect": "^0.2.1",
"effector-root": "^1.1.0",
"express": "^4.17.1",
Expand Down
19 changes: 5 additions & 14 deletions src/application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,14 @@ import { Pages } from './pages';
import { Globals } from './globals';

interface Props {
root: Scope;
scope: Scope;
}

export const Application: React.FC<Props> = ({ root }) => (
<Provider value={root}>
<Internal />
</Provider>
);

const Internal: React.FC = () => {
const readyToLoad = useEvent(readyToLoadSession);
React.useEffect(() => readyToLoad(), [readyToLoad]);

return (
export const Application: React.FC<Props> = ({ scope }) => (
<Provider value={scope}>
<>
<Globals />
<Pages />
</>
);
};
</Provider>
);
35 changes: 32 additions & 3 deletions src/client.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,48 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Router } from 'react-router';
import { matchRoutes } from 'react-router-config';
import { forward, root } from 'effector-root';
import { fork, hydrate } from 'effector/fork';

import { root } from 'effector-root';
import { history } from 'features/navigation';
import { getStart, lookupStartEvent, routeWithEvent } from 'lib/page-routing';
import { history, historyChanged } from 'features/navigation';
import { routes } from 'pages/routes';
import { Application } from './application';

hydrate(root, { values: INITIAL_STATE });

const scope = fork(root);

const routesMatched = historyChanged.map((change) => ({
routes: matchRoutes(routes, change.pathname).filter(lookupStartEvent),
query: Object.fromEntries(new URLSearchParams(change.search)),
}));

for (const { component } of routes) {
const startPageEvent = getStart(component);
if (!startPageEvent) continue;

const matchedRoute = routesMatched.filterMap(({ routes, query }) => {
const route = routes.find(routeWithEvent(startPageEvent));
if (route) return { route, query };
return undefined;
});

forward({
from: matchedRoute,
to: startPageEvent.prepend(({ route, query }) => ({
params: route.match.params,
query,
})),
});
}

// historyChanged({ action: 'REPLACE', ...history!.location });

ReactDOM.hydrate(
<Router history={history!}>
<Application root={scope} />
<Application scope={scope} />
</Router>,
document.querySelector('#root'),
);
Expand Down
11 changes: 11 additions & 0 deletions src/features/navigation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,23 @@ export const history =

export const $lastPushed = createStore('');

export interface HistoryChange {
pathname: string;
hash: string;
search: string;
action: 'PUSH' | 'POP' | 'REPLACE';
}
export const historyChanged = createEvent<HistoryChange>();

export const historyPush = createEvent<string>();
export const historyReplace = createEvent<string>();

if (process.env.BUILD_TARGET === 'client') {
historyPush.watch((url) => history!.push(url));
historyReplace.watch((url) => history!.replace(url));
history!.listen(({ pathname, search, hash }, action) => {
historyChanged({ pathname, search, hash, action });
});
} else {
const events = merge([historyPush, historyReplace]);
$lastPushed.on(events, (_, url) => url);
Expand Down
37 changes: 28 additions & 9 deletions src/lib/page-routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { Event, createEvent } from 'effector-root';
import { useEvent } from 'effector-react/ssr';
import { useParams, useLocation } from 'react-router';
import { MatchedRoute } from 'react-router-config';

const START = `☄️/start-event`;

Expand All @@ -21,17 +22,20 @@ export function createStart(...params: string[]): Event<StartParams> {
* Loads start event on browser side and pass params and query
*/
export function useStart(startEvent: Event<StartParams>) {
const params = useParams();
const location = useLocation();
const query = React.useMemo(
() => Object.fromEntries(new URLSearchParams(location.search)),
[],
console.warn(
'[deprecated] `useStart` is deprecated. Please, use `withStart` as HOC instead',
);
const start = useEvent(startEvent);
// const params = useParams();
// const location = useLocation();
// const query = React.useMemo(
// () => Object.fromEntries(new URLSearchParams(location.search)),
// [],
// );
// const start = useEvent(startEvent);

React.useEffect(() => {
start({ params, query });
}, []);
// React.useEffect(() => {
// start({ params, query });
// }, []);
}

/**
Expand All @@ -51,3 +55,18 @@ export function withStart<P extends Record<string, unknown>>(
component[START] = event;
return component;
}

export function lookupStartEvent<P>(
match: MatchedRoute<P>,
): Event<StartParams> | undefined {
if (match.route.component) {
return getStart(match.route.component);
}
return undefined;
}

export function routeWithEvent(event: Event<StartParams>) {
return function <P>(route: MatchedRoute<P>) {
return lookupStartEvent(route) === event;
};
}
4 changes: 1 addition & 3 deletions src/pages/access-recovery-confirm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Logo from 'logo.svg';
import { getValue } from 'lib/input';
import { CenterCardTemplate } from '@auth/ui';
import { changePassword } from 'api/access-recovery';
import { withStart, useStart } from 'lib/page-routing';
import { withStart } from 'lib/page-routing';

import * as model from './model';

Expand All @@ -32,8 +32,6 @@ const handlePasswordChanged = model.passwordChanged.prepend(getValue);
const handleRePasswordChanged = model.rePasswordChanged.prepend(getValue);

export const AccessRecoveryConfirmPage = withStart(model.pageStart, () => {
useStart(model.pageStart);

const formSubmitted = useEvent(model.formSubmitted);

const isPending = useStore(changePassword.pending);
Expand Down
7 changes: 3 additions & 4 deletions src/pages/access-recovery/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from 'react';
import React from 'react';
import styled from 'styled-components';
import { Button, Title, Input } from 'woly';
import { useStore, useEvent } from 'effector-react';
Expand All @@ -7,7 +7,7 @@ import Logo from 'logo.svg';
import { getValue } from 'lib/input';
import { CenterCardTemplate } from '@auth/ui';
import { sendRecoveryEmail } from 'api/access-recovery';
import { useStart, withStart } from 'lib/page-routing';
import { withStart } from 'lib/page-routing';

import * as model from './model';

Expand All @@ -24,8 +24,7 @@ const mapErrors = (error: model.AccessRecoveryError) => {
}
};

export const AccessRecoveryPage = withStart(model.start, () => {
useStart(model.start);
export const AccessRecoveryPage = withStart(model.pageLoaded, () => {
const formSubmitted = useEvent(model.formSubmitted);

const email = useStore(model.$email);
Expand Down
4 changes: 2 additions & 2 deletions src/pages/access-recovery/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { createStart } from 'lib/page-routing';

export type AccessRecoveryError = 'invalid_email' | 'fail_to_parse' | null;

export const start = createStart();
export const pageLoaded = createStart();
export const emailChanged = createEvent<string>();
export const formSubmitted = createEvent();

Expand All @@ -23,7 +23,7 @@ export const $failure = createStore<AccessRecoveryError>(null);
$email.on(emailChanged, (_, email) => email);

$failure
.reset(formSubmitted, start)
.reset(formSubmitted, pageLoaded)
.on(sendRecoveryEmail.failData, (_, { body }) => body.error)
.on(sendRecoveryEmail.failInvalid, () => 'fail_to_parse')
.on(emailChanged, (_, email) => {
Expand Down
14 changes: 5 additions & 9 deletions src/pages/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,11 @@ import styled from 'styled-components';
import { withStart, useStart } from 'lib/page-routing';
import * as model from './model';

export const HomePage = withStart(model.pageLoaded, () => {
useStart(model.pageLoaded);

return (
<section>
<h2>Hello world! Effector SSR example</h2>
</section>
);
});
export const HomePage = withStart(model.pageLoaded, () => (
<section>
<h2>Hello world! Effector SSR example</h2>
</section>
));

const Button = styled.button`
background-color: transparent;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/login/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ contract({
pageLoaded: model.start.prepend(noop),
formSubmitted: model.formSubmit.prepend(noop),
emailChanged: model.emailChange.prepend(getValue),
passwordChanged: model.emailChange.prepend(getValue),
passwordChanged: model.passwordChange.prepend(getValue),
},
});

Expand Down
74 changes: 35 additions & 39 deletions src/pages/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,41 @@ const $failureText = $failure.map((failure) => {
}
});

export const LoginPage = withStart(pageLoaded, () => {
useStart(pageLoaded);

return (
<CenterCardTemplate>
<Container>
<Logotype />

<Form>
<Title level={2}>Sign in</Title>
<ErrorBlock />

<Email placeholder="email" />
<Password type="password" placeholder="password" />

<Group>
<Submit variant="primary" />
<Button
as={Link}
to={path.register()}
text="Sign up"
variant="text"
/>
<Button
as={Link}
to={path.accessRecovery()}
text="Reset password"
variant="text"
/>
</Group>
</Form>
<Footer>
By joining nameproject you accept our Terms of Service and Privacy
Policy
</Footer>
</Container>
</CenterCardTemplate>
);
});
export const LoginPage = withStart(pageLoaded, () => (
<CenterCardTemplate>
<Container>
<Logotype />

<Form>
<Title level={2}>Sign in</Title>
<ErrorBlock />

<Email placeholder="email" />
<Password type="password" placeholder="password" />

<Group>
<Submit variant="primary" />
<Button
as={Link}
to={path.register()}
text="Sign up"
variant="text"
/>
<Button
as={Link}
to={path.accessRecovery()}
text="Reset password"
variant="text"
/>
</Group>
</Form>
<Footer>
By joining nameproject you accept our Terms of Service and Privacy
Policy
</Footer>
</Container>
</CenterCardTemplate>
));

const Form = reflect({
view: styled.form``,
Expand Down
11 changes: 4 additions & 7 deletions src/pages/oauth/authorize/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import * as React from 'react';
import { withStart, useStart } from 'lib/page-routing';
import React from 'react';
import { withStart } from 'lib/page-routing';

import * as model from './model';

export const OAuthAuthorizePage = () => {
// useStart(model.pageLoaded);

export const OAuthAuthorizePage = withStart(model.pageLoaded, () => {
return null;
};
withStart(model.pageLoaded, OAuthAuthorizePage);
});
2 changes: 1 addition & 1 deletion src/pages/oauth/authorize/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { checkAuthenticated } from 'features/session';
import { oauthAuthorize } from 'api/oauth';
import { historyPush } from 'features/navigation';
import { debug } from 'patronum/debug';
console.log('EXAMPLE');

export const pageLoaded = createStart();

const pageReady = checkAuthenticated({ when: pageLoaded });
Expand Down
2 changes: 0 additions & 2 deletions src/pages/register/confirm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import Logo from 'logo.svg';
import * as model from './model';

export const RegisterConfirmPage = withStart(model.pageStart, () => {
useStart(model.pageStart);

const isSubmitDisabled = useStore(model.$isSubmitDisabled);
const isRegistrationFinished = useStore(model.$isRegistrationFinished);
const formSubmitted = useEvent(model.formSubmitted);
Expand Down

0 comments on commit 813df4c

Please sign in to comment.