Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Angular使いがReactでアプリ組んだらこうなった
Search
puku0x
June 05, 2019
Technology
1.9k
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
1
1.8k
新メンバーのために、シニアエンジニアが環境を作る時代
puku0x
0
1.6k
Agent Skills 入門
puku0x
0
2.4k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
2.3k
生成AIではじめるテスト駆動開発
puku0x
0
1.6k
実践!カスタムインストラクション&スラッシュコマンド
puku0x
2
3.5k
Nx × AI によるモノレポ活用 〜コードジェネレーター編〜
puku0x
0
1.8k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
330
ファインディでのGitHub Actions活用事例
puku0x
9
4k
Other Decks in Technology
See All in Technology
サブエージェントと Claude Mods で作る独自 Advisor ツールの話
kenichiodo
2
160
味覇で作るパスタが美味い - 20261001_yabaubuki.dev
livesense
PRO
0
130
今さら理解するウェブフォントver.2026
takanorip
3
710
V8のArray.prototype.flatを最大約20倍速くするまでと、巨大OSSへの大規模コミットの道のり
riyaamemiya
0
290
Kiro Crewをはじめよう
kizawa2020
1
150
自作バイナリを動かす「入口」8選
puhitaku
2
1.3k
しろおびから始める!ログ活用の第一歩
shumei_ito
0
940
無理せず続ける、子育てエンジニアの学び
codmoninc
PRO
0
750
宣言型部分更新は何を解決しどこへ向かうのか
shuta13
1
430
USB PDを使ってスマホを労わりたい
raspython3
0
170
実体験から学ぶ分析エージェントの開発と運⽤
recruitengineers
PRO
8
2.3k
NDIでApple Vision Proにリアルタイム映像送信
jyouryuusui
0
120
Featured
See All Featured
KATA
mclloyd
PRO
35
16k
Code Reviewing Like a Champion
maltzj
529
40k
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
300
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Being A Developer After 40
akosma
92
590k
WENDY [Excerpt]
tessaabrams
14
40k
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
270
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Building AI with AI
inesmontani
PRO
1
1.3k
Building the Perfect Custom Keyboard
takai
2
900
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
430
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