Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular使いがReactでアプリ組んだらこうなった

puku0x
June 05, 2019

 Angular使いがReactでアプリ組んだらこうなった

React勉強会@福岡 vol.2

puku0x

June 05, 2019
Tweet

More Decks by puku0x

Other Decks in Technology

Transcript

  1. Angular使いが
    Reactでアプリ組んだらこうなった
    React勉強会@福岡 vol.2

    View full-size slide

  2. Noriyuki
    Shinpuku
    ng-fukuoka organizer
    VEGA corporation Co., Ltd.
    @puku0x

    View full-size slide

  3. Supported by Google

    View full-size slide

  4. Full-fledged & opinionated
    Angular Protractor Forms PWA Augury
    Language
    Services
    Router Elements CDK
    Universal Karma Labs Compiler i18n Http Material Animations CLI

    View full-size slide

  5. Supported by Facebook

    View full-size slide

  6. React is a library

    View full-size slide

  7. Scalable apps with React?

    View full-size slide

  8. 1. Use TypeScript
    $ npm i -D @types/{react,react-dom}

    View full-size slide

  9. 2. Abstraction
    ● Keep components SIMPLE
    ● Better testability
    Component Service HttpClient Axios

    View full-size slide

  10. HttpClient (inspired by Angular’s HttpClient)
    export abstract class HttpClient {
    abstract get(url: string, options?: HttpRequestOptions)
    abstract post(url: string, data?: unknown, options?: HttpRequestOptions)
    abstract put(url: string, data?: unknown, options?: HttpRequestOptions)
    abstract delete(url: string, options?: HttpRequestOptions)
    }

    View full-size slide

  11. Services
    const fetchUser = async (id: number) => {
    const res = await httpClient.get(`/users/${id}`);
    return res.data;
    };
    export const UserService = {
    fetch: fetchUser,
    ...
    };

    View full-size slide

  12. 3. Separation of concerns
    ● Business logic
    ● State management
    ● Components

    View full-size slide

  13. State management
    ● react-redux + redux-thunk + re-ducks pattern
    ● Keep reducers PURE
    ● Good practices from NgRx
    ○ Good Action Hygiene
    ○ Entity pattern

    View full-size slide

  14. Good Action Hygiene
    export enum UserActionTypes {
    // ACTION_NAME = '[Source] Event',
    FETCH_REQUEST = '[User/Page] Fetch Request',
    FETCH_SUCCESS = '[User/API] Fetch Success',
    FETCH_FAILURE = '[User/API] Fetch Failure',
    ...
    }
    Good Action Hygiene with NgRx Mike Ryan
    https://www.youtube.com/watch?v=JmnsEvoy-gY

    View full-size slide

  15. Thunk Actions
    export interface FetchUserRequest extends Action {
    payload: { id: number };
    }
    export function fetchUserRequest(id: number): ThunkAction, State, undefined, Actions> {
    return async dispatch => {
    dispatch({ type: UserActionTypes.FETCH_REQUEST, payload: { id } });
    const result = await UserService.fetch(id)
    .then(response => fetchUserSuccess(response))
    .catch(error => fetchUserFailure(error));
    return dispatch(result);
    };
    }

    View full-size slide

  16. Entity pattern
    interface Dictionary {
    [id: number]: T;
    }
    export interface EntityState {
    ids: number[];
    entities: Dictionary;
    }

    View full-size slide

  17. EntityAdapter (inspired by NgRx’s EntityAdapter)
    export const adapter: EntityAdapter = createEntityAdapter();
    export function reducer(state = initialState, action: Action): State {
    switch (action.type) {
    ...
    case UserActionTypes.UPDATE_SUCCESS: {
    const { user } = action.payload;
    return adapter.update(user, { ...state, isFetching: false });
    }
    ...
    }
    }
    Immutable operation with less boilerplates

    View full-size slide

  18. Selectors
    const usersStateSelector = (state: { users: UserState }) => state.users;
    const { selectAll, selectEntities } = adapter.getSelectors();
    export const usersSelector = createSelector(
    usersStateSelector,
    selectAll
    );

    View full-size slide

  19. 3. Separation of concerns (for components)
    ● Business logic
    ● State management
    ● Components
    ○ Page components
    ○ Container components
    ○ Presentational components

    View full-size slide

  20. Structure of components
    Page component
    Router params
    Store
    Container components
    Presentational components
    http://localhost:3000/users/:id

    View full-size slide

  21. Page components
    type Props = RouteComponentProps<{ id: string }>;
    const UserDetailPage: FunctionComponent = props => {
    const { match, location } = props;
    const { id } = match.params;
    const params = new URLSearchParams(location.search);
    const edit = params.get('edit') || false;
    return ;
    };
    export default withRouter(UserDetailPage);

    View full-size slide

  22. Container components
    type Props = {
    id: number;
    };
    export const UserDetail: FunctionComponent = props => {
    const { id } = props;
    const user = useSelector(userSelector);
    const dispatch = useDispatch();
    useEffect(() => dispatch(fetchUserRequest(id)), [id]);
    return ;
    };

    View full-size slide

  23. Presentational components
    type Props = RouteComponentProps & {
    user: User;
    };
    const UserDetailComponent: FunctionComponent = props => {
    const { user, history } = props;
    const goBack = useCallback(() => history.goBack(), []);
    return <>...>
    };
    export const UserDetail = withRouter(UserDetailComponent);

    View full-size slide

  24. 4. Lazy loading
    ● Suspense + lazy()
    ● Route-based lazy loading
    import { lazy } from 'react';
    export const UsersPage = lazy(() => import('./UsersPage'));

    View full-size slide

  25. Routing separation
    Loading...}>

    } />





    “Separation of concerns” for routing

    View full-size slide

  26. Routing separation for child pages
    const UsersPage: FunctionComponent = () => (
    Loading...}>







    );
    export default UsersPage;

    View full-size slide

  27. src/
    models/
    user.model.ts
    index.ts
    pages/
    UsersPage/
    UserDetailPage/
    components/
    containers/
    UserDetailPage.tsx
    index.ts
    UsersPage.tsx
    index.ts
    MainPage/
    index.ts
    5. Naming & structuring like way
    shared/
    components/
    Button/
    Button.tsx
    Button.test.tsx
    Button.stories.tsx
    index.ts
    helpers/
    hooks/
    index.ts
    :
    App.tsx
    AuthenticatedRoute.tsx
    index.tsx
    index.html
    services/
    user/
    user.service.ts
    user.service.test.ts
    index.ts
    store/
    user/
    actions/
    user.action.ts
    user.action.test.ts
    index.ts
    reducers/
    selectors/
    states/
    index.ts
    https://angular.io/guide/styleguide

    View full-size slide

  28. Other libraries?

    View full-size slide

  29. Styling
    ● emotion
    ● classnames

    View full-size slide

  30. Form validation
    ● Formik (v1.5)
    ○ v2.0.1-rc.x is not recommended
    https://github.com/jaredpalmer/formik/pull/1570
    ● Yup

    View full-size slide

  31. Routing
    ● react-router (v5.0)
    ● connected-react-router
    const middleware =
    process.env.NODE_ENV !== 'production'
    ? [require('connected-react-router/immutable').routerMiddleware(history), thunk]
    : [require('connected-react-router').routerMiddleware(history), thunk];
    const middlewares = applyMiddleware(...middleware);

    View full-size slide

  32. State management
    ● react-redux (v7.1)
    ○ Requires adding custom @types/react-redux
    ● redux-thunk
    ○ Requires overloading redux’s Dispatch
    https://github.com/reduxjs/redux-thunk/pull/247
    ● reselect

    View full-size slide

  33. Testing
    ● jest
    ● enzyme
    ● react-test-renderer
    ● redux-mock-store

    View full-size slide

  34. Follow good practices

    View full-size slide

  35. One more option

    View full-size slide

  36. We don’t use create-react-app
    Because it doesn’t allow us to use path alias.

    View full-size slide

  37. ● Type safe
    ● Simple
    ● Easy to refactor
    ● Performant
    ● Scalable

    View full-size slide

  38. Summary
    ● The experience of helped us to make app
    ○ Using TypeScript
    ○ Abstraction
    ○ Separation of concerns
    ○ Lazy loading
    ○ Naming

    View full-size slide

  39. Always keep an open mind

    View full-size slide

  40. Thank you!
    @puku0x
    Noriyuki Shinpuku

    View full-size slide