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
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.7k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
310
ファインディでのGitHub Actions活用事例
puku0x
9
3.9k
Findyの開発生産性向上への取り組み ~Findyフロントエンドの場合~
puku0x
0
490
Other Decks in Technology
See All in Technology
カードゲーム作りが教えてくれた プロダクトオーナーシップ
moritamasami
0
110
あなたの『Site』はどこですか? — xREという考え方
miyamu
0
1.2k
Control Planeで育てるBtoB SaaSの認証基盤 - SRE NEXT 2026
pokohide
1
2.6k
CSに"SLO"は要らない、経営層に"99.9%"は伝わらない - SREを全社に"翻訳"する3原則
cscengineer
PRO
1
5k
しぶいSRE: サーバから見えない障害にどう向き合うか。ラストワンマイルのデバッグ実践 / Shibui SRE
kanny
13
6.5k
Gen3R: 3D Scene Generation Meets Feed-Forward Reconstruction
spatial_ai_network
0
130
はじめてのWDM
miyukichi_ospf
1
150
LLM/Agent評価:トップ営業の発言を「正解」にする 〜暗黙的正解による評価を営業資産に変える〜
takkuhiro
1
230
[2026-07-15] AI Ready なはずだったアーキテクチャと、見えてきた課題・次に目指す状態
wxyzzz
9
4k
AIが実装を自走する時代の認知負債との戦い
lycorptech_jp
PRO
0
140
タスクの複雑さでモデルを選ぶ ── Thompson Samplingで動かす“トークン/コスト最適化
satohy0323
0
550
AIと共生する開発者プラットフォーム:バクラクのモノレポ×マイクロサービス基盤
sakajunquality
2
3.7k
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
187
22k
Producing Creativity
orderedlist
PRO
348
40k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
240
Code Review Best Practice
trishagee
74
20k
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
Darren the Foodie - Storyboard
khoart
PRO
3
3.4k
Fireside Chat
paigeccino
42
4k
Why Our Code Smells
bkeepers
PRO
340
58k
Into the Great Unknown - MozCon
thekraken
41
2.6k
Prompt Engineering for Job Search
mfonobong
0
380
Testing 201, or: Great Expectations
jmmastey
46
8.2k
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