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
1
550
新メンバーのために、シニアエンジニアが環境を作る時代
puku0x
0
1.6k
Agent Skills 入門
puku0x
0
2k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
2.2k
生成AIではじめるテスト駆動開発
puku0x
0
1.5k
実践!カスタムインストラクション&スラッシュコマンド
puku0x
2
3.4k
Nx × AI によるモノレポ活用 〜コードジェネレーター編〜
puku0x
0
1.7k
ファインディにおけるフロントエンド技術選定の歴史
puku0x
2
320
ファインディでのGitHub Actions活用事例
puku0x
9
3.9k
Other Decks in Technology
See All in Technology
Breaking the Seal: Static Deobfuscation of Compiled V8 JavaScript Bytecode Malware
hshrzd
0
740
JavaScript 研修 (2026)
recruitengineers
PRO
2
530
モノリス Rails でも日中に rails db:migrate を走らせたい! / Daytime rails db:migrate on Monolithic Rails!
euglena1215
4
580
Flutterをカメラで動かしたかった話
sony
1
140
ブラウザ研修 2026
recruitengineers
PRO
6
980
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
『三匹の子ぶた』から学ぶネットワークセキュリティの昔と今 / Network Security: Then and Now Through the Lens of The Three Little Pigs
nttcom
1
1.8k
QAエンジニア起点で進める、SmartHRにおける信頼性向上について
kaomi_wombat
1
140
SO-101×VLAによる3色キューブのピック&プレース
abeja
0
200
MIRU 2026 チュートリアル
keisuke198619
0
910
AIペネトレーションテスト・ セキュリティ検証「AgenticSec」紹介資料
laysakura
2
9k
その“隠したつもり”が命取り ── 自前と平文をやめて「正解」に委ねる
kuroneko13
0
120
Featured
See All Featured
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
470
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
1.1k
New Earth Scene 8
popppiees
3
2.5k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
390
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.8k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
270
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
56k
How to build a perfect <img>
jonoalderson
1
5.9k
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