Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
frontend_validation.pdf
ktp
September 04, 2019
Programming
2
810
frontend_validation.pdf
ktp
September 04, 2019
Tweet
Share
More Decks by ktp
See All by ktp
kato1628
1
150
Other Decks in Programming
See All in Programming
yosuke_furukawa
PRO
14
3.7k
siketyan
1
110
line_developers_tw
0
1.2k
jun0
3
640
anchorcable
1
120
kenmaz
1
100
dulltz
0
500
adoranwodo
0
220
atskimura
0
290
itosho525
0
360
showwin
0
120
akatsukinewgrad
0
160
Featured
See All Featured
jasonvnalue
82
8k
addyosmani
310
21k
pedronauck
652
110k
nonsquared
81
3.3k
smashingmag
229
18k
edds
56
9.3k
ufuk
56
5.4k
shpigford
165
19k
sugarenia
233
830k
3n
163
22k
caitiem20
308
17k
carmenhchung
26
1.3k
Transcript
Redux middleware Ͱ ϑϩϯτΤϯυόϦσʔγϣϯ Λ࣮͢Δ @kato1628
@kato1628 ɾReact, Redux, TypeScript ɾSudachi ɾSwimming
Demo
redux flow
redux flow ʮͲ͏มߋ͞ΕΔ͔ʯˡ ʮͲ͏ৼΔ͏͔ʯˡ ʮͲ͏ݟ͑Δ͔ʯˡ
ͲͷϨΠϠʔԚͨ͘͠ͳ͍
redux flow (with validation middleware) ಛఆͷBDUJPO͕EJTQBUDI͞Εͨ߹ʹͷΈɺ WBMJEBUJPOΛ࣮ߦ͢Δɻ FSSPSTUBUF
Motivation • Fat component/container ͷճආ • ಠཱͨ͠ػߏͰ࣮ ≒ ͷ •
֎෦ϥΠϒϥϦͷґଘճආ • Ұͭͷػߏʹ validation Λू
state ͷఆٛ // ͜ΜͳΤϥʔϝοηʔδΛ state ʹ͍࣋ͪͨ errors = { email:
"Email is required" … }
ΤϥʔϝοηʔδͷܕΛఆٛ # src/reducers/errors.tsx + type ValidateStates = "email"; + type
ErrorMessage = string; + type Errors = { [key in ValidateStates]?: ErrorMessage }
actionΛఆٛ
actionΛఆٛ # src/actions/actions.tsx + export const validationSuccess = (key: ValidateStates)
=> ({ + type: AppActionTypes.VALIDATION_SUCCESS as const, + key + }); + export const validationFailure = (errors: Errors) => ({ + type: AppActionTypes.VALIDATION_FAILURE as const, + errors + });
reducerΛఆٛ
reducerΛఆٛ # src/reducers/errors.tsx export const errors = (state = initialErrors,
action: AppAction): Errors => { switch (action.type) { + case AppActionTypes.VALIDATION_FAILURE: // ࣦഊ࣌ + return { + ...state, + ...action.errors + }; + case AppActionTypes.VALIDATION_SUCCESS: // ޭ࣌ + const nextState = { ...state }; + delete nextState[action.key]; + return nextState; default: return state; }
✓ state (ͲΜͳ͔) ✓ action (Կ͕ى͜Δ͔) ✓ reducer (Ͳ͏มߋ͞ΕΔ͔) ☐
validation middleware (Ͳ͏ఆ͢Δ͔)
validation middleware ͷ ☑ ఆϩδοΫ => ඞਢνΣοΫɺܻνΣοΫɺ֯ࣈνΣοΫ…etc ☑ ఆ݁Ռͷө =>
action ͷ dispatch
ఆϩδοΫ
validator • จࣈྻόϦσʔγϣϯ • ๛ͳόϦσʔγϣϯϝιου https://github.com/validatorjs/validator.js $ yarn add validator
@types/validator # Example var validator = require('validator'); validator.isEmail('foo@bar.com'); //=> true
middlewareͷ࣮
What is middleware? • redux ͷ dispatch Λ֦ு͢Δػߏ • ϐϡΞͳ
dispatch ϓϨʔϯͳΦϒδΣΫτ͔͠ड͚ औΕͳ͍ • Ex redux-thunk
dispatch ʮSFEVDFSʹBDUJPOΛͯ͠TUBUFΛߋ৽͢Δʯˡ
Ex. redux-thunk ແ͠ // action ϓϨʔϯͳΦϒδΣΫτΛฦ͢ const increment = ()
=> { return { type: INCREMENT_COUNTER, }; } // dispatch ϓϨʔϯͳΦϒδΣΫτͷΈड͚औΕΔ dispatch(increment())
Ex. redux-thunk ༗Γ // function Λฦ͢ action Λఆٛ const incrementAsync
= () => { return (dispatch) => { setTimeout(() => { // Yay! Can invoke sync or async actions with `dispatch` dispatch(increment()); // ͦͷதͰ͞Βʹ action Λ dispatch }, 1000); }; } // dispatch function ड͚औΕΔ dispatch(incrementAsync())
middlewareͷܕ
middlewareͷܕ # src/node_modules/redux/index.d.ts export interface Middleware< DispatchExt = {}, S
= any, D extends Dispatch = Dispatch > { (api: MiddlewareAPI<D, S>): ( next: Dispatch<AnyAction> ) => (action: any) => any } => ؔΛฦؔ͢Λฦؔ͢ => ܹ͍͠ΧϦʔԽ
ͪΐͬͱ ԿݴͬͯΔ͔Θ͔Βͳ͍
middlewareͷجຊܗ const validator = ({ dispatch, getState }) => next
=> action => { // ͜͜ʹఆϩδοΫͱɺaction dispatch Λ࣮ // ࣍ͷ middleware ·ͨ store ͷ dispatch ͕ݺͼग़͞ΕΔ return next(action); };
middlewareͷجຊܗ (ܕ༗Γ) + const validator = ({ dispatch, getState }:
MiddlewareAPI<AppThunkDispatch>) => ( + next: Dispatch + ) => (action: AppAction) => { + return next(action); + }; + + export default validator;
middlewareͷ࣮ const validator = ({ dispatch, getState }: MiddlewareAPI<AppThunkDispatch>) =>
( next: Dispatch ) => (action: AppAction) => { + switch (action.type) { + case AppActionTypes.UPDATE_EMAIL: // dispatchʹόϦσʔγϣϯؔΛ͢ʢredux-thunk Λ༻ʣ + dispatch(validateEmail(action.email)); + break; + default: + break; } return next(action); }; export default validator;
όϦσʔγϣϯؔ (thunk actin) + const validateEmail = (email: string): AppThunkAction<void>
=> dispatch => { + let errorMessage: string = ""; // validator ΛͬͯඞਢνΣοΫ + if (isEmpty(email)) { + errorMessage = "Email is required."; + } + if (errorMessage === "") { + dispatch(validationSuccess(“email")); // ޭ࣌ + } else { + dispatch(validationFailure({ email: errorMessage })); // ࣦഊ࣌ + } + };
validation middleware • ఆϩδοΫΛ࣮ߦ • ޭɾࣦഊͦΕͧΕͷ action Λ dispatch •
validationSuccess • validationFailure
# src/index.tsx + import thunk from “redux-thunk"; + import validator
from "./middleware/validator"; - const store = createStore(reducer) + const store = createStore(reducer, applyMiddleware(thunk, validator)); applyMiddleware
# src/containers/AppContainer.tsx + const mapStateToProps = (state: AppState) => ({
+ errors: state.errors + }); # src/components/App.tsx + const App: React.FC<AppProps> = ({ errors, onChangeEmail }) => { ~~ + <p>{errors.email}</p> display errors
Complete!
Pros • Fat component/container ͷճආ • ಠཱͨ͠ػߏͰ࣮ ≒ ͷ •
֎෦ϥΠϒϥϦͷґଘճආ • Ұͭͷػߏʹ validation Λू
Cons • Component ͔Βԕ͍ॴʹ validation ͕࣮ ͞ΕΔ • middleware ΛΒͳ͍ͱཧղ͕͍͠
Source https://github.com/kato1628/frontend-validation
Thank you!