Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Angular使いがReactでアプリ組んだらこうなった
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
puku0x
June 05, 2019
Technology
1.8k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Angular使いがReactでアプリ組んだらこうなった
React勉強会@福岡 vol.2
puku0x
June 05, 2019
More Decks by puku0x
See All by puku0x
新メンバーのために、シニアエンジニアが環境を作る時代
puku0x
0
1.5k
Agent Skills 入門
puku0x
0
1.9k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
2.1k
生成AIではじめるテスト駆動開発
puku0x
0
1.4k
実践!カスタムインストラクション&スラッシュコマンド
puku0x
2
3.3k
Nx × AI によるモノレポ活用 〜コードジェネレーター編〜
puku0x
0
1.6k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
300
ファインディでのGitHub Actions活用事例
puku0x
9
3.9k
Findyの開発生産性向上への取り組み ~Findyフロントエンドの場合~
puku0x
0
480
Other Decks in Technology
See All in Technology
いまさら聞けない人のためのAIコーディング入門
devops_vtj
0
120
Rancherの紹介&Update情報(RancherJP Online Meetup #09)
yoshiyuki_kono
0
130
Oracle AI Database@Google Cloud:サービス概要のご紹介
oracle4engineer
PRO
6
1.5k
Socrates × Looker 〜セマンティックレイヤーで進化するデータ分析エージェント〜
hanon52_
0
330
AI-DLCを活用した高品質・安全なAI駆動開発実践 / AI Driven Development
yoshidashingo
1
380
Platform Engineering as a Product: Criteria for Improvement and Multi-Tenant Design
kumorn5s
0
520
個人の発見を、組織の知恵に 〜生成AI活用を"探索"から"組織の仕組み"へ〜
kintotechdev
2
1.1k
サイバーセキュリティ概論 / Introduction to Cybersecurity
ks91
PRO
0
170
ルールやカスタム機能、どう使う?理想の出力を引き出すために今知りたいIBM Bob 5つの機能
muehara
1
360
Dario Amodi『Policy on the AI Exponential』を理解する
nagatsu
0
200
ITエンジニアを取り巻く環境とキャリアパス / A career path for Japanese IT engineers
takatama
4
1.8k
運用を見据えたAIエージェント設計実践
amacbee
1
3.2k
Featured
See All Featured
The Pragmatic Product Professional
lauravandoore
37
7.3k
SEO Brein meetup: CTRL+C is not how to scale international SEO
lindahogenes
1
2.7k
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Mobile First: as difficult as doing things right
swwweet
225
10k
Into the Great Unknown - MozCon
thekraken
41
2.5k
Building AI with AI
inesmontani
PRO
1
1.1k
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
160
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
65
56k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
200
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.7k
Transcript
Angular使いが Reactでアプリ組んだらこうなった React勉強会@福岡 vol.2
Noriyuki Shinpuku ng-fukuoka organizer VEGA corporation Co., Ltd. @puku0x
Angular
Supported by Google
Full-fledged & opinionated Angular Protractor Forms PWA Augury Language Services
Router Elements CDK Universal Karma Labs Compiler i18n Http Material Animations CLI
React
Supported by Facebook
React is a library
Scalable apps with React?
1. Use TypeScript $ npm i -D @types/{react,react-dom}
2. Abstraction • Keep components SIMPLE • Better testability Component
Service HttpClient Axios
HttpClient (inspired by Angular’s HttpClient) export abstract class HttpClient {
abstract get<T>(url: string, options?: HttpRequestOptions) abstract post<T>(url: string, data?: unknown, options?: HttpRequestOptions) abstract put<T>(url: string, data?: unknown, options?: HttpRequestOptions) abstract delete(url: string, options?: HttpRequestOptions) }
Services const fetchUser = async (id: number) => { const
res = await httpClient.get<User>(`/users/${id}`); return res.data; }; export const UserService = { fetch: fetchUser, ... };
3. Separation of concerns • Business logic • State management
• Components
State management • react-redux + redux-thunk + re-ducks pattern •
Keep reducers PURE • Good practices from NgRx ◦ Good Action Hygiene ◦ Entity pattern
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
Thunk Actions export interface FetchUserRequest extends Action<UserActionTypes.FETCH_REQUEST> { payload: {
id: number }; } export function fetchUserRequest(id: number): ThunkAction<Promise<Success | Failure>, State, undefined, Actions> { return async dispatch => { dispatch<FetchUserRequest>({ type: UserActionTypes.FETCH_REQUEST, payload: { id } }); const result = await UserService.fetch(id) .then(response => fetchUserSuccess(response)) .catch(error => fetchUserFailure(error)); return dispatch(result); }; }
Entity pattern interface Dictionary<T> { [id: number]: T; } export
interface EntityState<T> { ids: number[]; entities: Dictionary<T>; }
EntityAdapter (inspired by NgRx’s EntityAdapter) export const adapter: EntityAdapter<User> =
createEntityAdapter<User>(); 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
Selectors const usersStateSelector = (state: { users: UserState }) =>
state.users; const { selectAll, selectEntities } = adapter.getSelectors(); export const usersSelector = createSelector( usersStateSelector, selectAll );
3. Separation of concerns (for components) • Business logic •
State management • Components ◦ Page components ◦ Container components ◦ Presentational components
Structure of components Page component Router params Store Container components
Presentational components http://localhost:3000/users/:id
Page components type Props = RouteComponentProps<{ id: string }>; const
UserDetailPage: FunctionComponent<Props> = props => { const { match, location } = props; const { id } = match.params; const params = new URLSearchParams(location.search); const edit = params.get('edit') || false; return <UserDetail id={+id} edit={+edit} />; }; export default withRouter(UserDetailPage);
Container components type Props = { id: number; }; export
const UserDetail: FunctionComponent<Props> = props => { const { id } = props; const user = useSelector(userSelector); const dispatch = useDispatch(); useEffect(() => dispatch(fetchUserRequest(id)), [id]); return <UserDetailComponent user={user} />; };
Presentational components type Props = RouteComponentProps & { user: User;
}; const UserDetailComponent: FunctionComponent<Props> = props => { const { user, history } = props; const goBack = useCallback(() => history.goBack(), []); return <>...</> }; export const UserDetail = withRouter(UserDetailComponent);
4. Lazy loading • Suspense + lazy() • Route-based lazy
loading import { lazy } from 'react'; export const UsersPage = lazy(() => import('./UsersPage'));
Routing separation <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/" render={() =>
<Redirect to="/dashboard" />} /> <Route path="/dashboard" component={DashboardPage} /> <Route path="/groups" component={GroupsPage} /> <Route path="/users" component={UsersPage} /> </Switch> </Suspense> “Separation of concerns” for routing
Routing separation for child pages const UsersPage: FunctionComponent = ()
=> ( <Suspense fallback={<div>Loading...</div>}> <Switch> <Route exact path="/users" component={UserListPage} /> <Route exact path="/users/new" component={UserCreatePage} /> <Route exact path="/users/:id"component={UserDetailPage} /> <Route exact path="/users/:id/edit" component={UserEditPage} /> </Switch> </Suspense> ); export default UsersPage;
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
Other libraries?
Styling • emotion • classnames
Form validation • Formik (v1.5) ◦ v2.0.1-rc.x is not recommended
https://github.com/jaredpalmer/formik/pull/1570 • Yup
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);
State management • react-redux (v7.1) ◦ Requires adding custom @types/react-redux
• redux-thunk ◦ Requires overloading redux’s Dispatch<Action> https://github.com/reduxjs/redux-thunk/pull/247 • reselect
Testing • jest • enzyme • react-test-renderer • redux-mock-store
Follow good practices
One more option
We don’t use create-react-app Because it doesn’t allow us to
use path alias.
How was it?
Awesome!
• Type safe • Simple • Easy to refactor •
Performant • Scalable
Summary • The experience of helped us to make app
◦ Using TypeScript ◦ Abstraction ◦ Separation of concerns ◦ Lazy loading ◦ Naming
Always keep an open mind
Thank you! @puku0x Noriyuki Shinpuku