Slide 1

Slide 1 text

Redux middleware Ͱ ϑϩϯτΤϯυόϦσʔγϣϯ Λ࣮૷͢Δ @kato1628

Slide 2

Slide 2 text

@kato1628 ɾReact, Redux, TypeScript ɾSudachi ɾSwimming

Slide 3

Slide 3 text

Demo

Slide 4

Slide 4 text

redux flow

Slide 5

Slide 5 text

redux flow ʮͲ͏มߋ͞ΕΔ͔ʯˡ ʮͲ͏ৼΔ෣͏͔ʯˡ ʮͲ͏ݟ͑Δ͔ʯˡ

Slide 6

Slide 6 text

ͲͷϨΠϠʔ΋Ԛͨ͘͠ͳ͍

Slide 7

Slide 7 text

redux flow (with validation middleware) ಛఆͷBDUJPO͕EJTQBUDI͞Εͨ৔߹ʹͷΈɺ WBMJEBUJPOΛ࣮ߦ͢Δɻ FSSPSTUBUF

Slide 8

Slide 8 text

Motivation • Fat component/container ͷճආ • ಠཱͨ͠ػߏͰ࣮૷ ≒ ੹຿ͷ෼཭ • ֎෦ϥΠϒϥϦ΁ͷґଘճආ • Ұͭͷػߏʹ validation Λू໿

Slide 9

Slide 9 text

state ͷఆٛ // ͜ΜͳΤϥʔϝοηʔδΛ state ʹ͍࣋ͪͨ errors = { email: "Email is required" … }

Slide 10

Slide 10 text

ΤϥʔϝοηʔδͷܕΛఆٛ # src/reducers/errors.tsx + type ValidateStates = "email"; + type ErrorMessage = string; + type Errors = { [key in ValidateStates]?: ErrorMessage }

Slide 11

Slide 11 text

actionΛఆٛ

Slide 12

Slide 12 text

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 + });

Slide 13

Slide 13 text

reducerΛఆٛ

Slide 14

Slide 14 text

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; }

Slide 15

Slide 15 text

✓ state (ͲΜͳ஋͔) ✓ action (Կ͕ى͜Δ͔) ✓ reducer (Ͳ͏มߋ͞ΕΔ͔) ☐ validation middleware (Ͳ͏൑ఆ͢Δ͔)

Slide 16

Slide 16 text

validation middleware ͷ੹຿ ☑ ൑ఆϩδοΫ => ඞਢνΣοΫɺܻ਺νΣοΫɺ൒֯਺ࣈνΣοΫ…etc ☑ ൑ఆ݁Ռͷ൓ө => action ͷ dispatch

Slide 17

Slide 17 text

൑ఆϩδοΫ

Slide 18

Slide 18 text

validator • จࣈྻόϦσʔγϣϯ • ๛෋ͳόϦσʔγϣϯϝιου https://github.com/validatorjs/validator.js $ yarn add validator @types/validator # Example var validator = require('validator'); validator.isEmail('[email protected]'); //=> true

Slide 19

Slide 19 text

middlewareͷ࣮૷

Slide 20

Slide 20 text

What is middleware? • redux ͷ dispatch Λ֦ு͢Δػߏ • ϐϡΞͳ dispatch ͸ϓϨʔϯͳΦϒδΣΫτ͔͠ड͚ औΕͳ͍ • Ex redux-thunk

Slide 21

Slide 21 text

dispatch ʮSFEVDFSʹBDUJPOΛ౉ͯ͠TUBUFΛߋ৽͢Δʯˡ

Slide 22

Slide 22 text

Ex. redux-thunk ແ͠ // action ͸ϓϨʔϯͳΦϒδΣΫτΛฦ͢ const increment = () => { return { type: INCREMENT_COUNTER, }; } // dispatch ͸ϓϨʔϯͳΦϒδΣΫτͷΈड͚औΕΔ dispatch(increment())

Slide 23

Slide 23 text

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())

Slide 24

Slide 24 text

middlewareͷܕ

Slide 25

Slide 25 text

middlewareͷܕ # src/node_modules/redux/index.d.ts export interface Middleware< DispatchExt = {}, S = any, D extends Dispatch = Dispatch > { (api: MiddlewareAPI): ( next: Dispatch ) => (action: any) => any } => ؔ਺Λฦؔ͢਺Λฦؔ͢਺ => ܹ͍͠ΧϦʔԽ

Slide 26

Slide 26 text

ͪΐͬͱ ԿݴͬͯΔ͔Θ͔Βͳ͍

Slide 27

Slide 27 text

middlewareͷجຊܗ const validator = ({ dispatch, getState }) => next => action => { // ͜͜ʹ൑ఆϩδοΫͱɺaction dispatch Λ࣮૷ // ࣍ͷ middleware ·ͨ͸ store ͷ dispatch ͕ݺͼग़͞ΕΔ return next(action); };

Slide 28

Slide 28 text

middlewareͷجຊܗ (ܕ༗Γ) + const validator = ({ dispatch, getState }: MiddlewareAPI) => ( + next: Dispatch + ) => (action: AppAction) => { + return next(action); + }; + + export default validator;

Slide 29

Slide 29 text

middlewareͷ࣮૷ const validator = ({ dispatch, getState }: MiddlewareAPI) => ( 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;

Slide 30

Slide 30 text

όϦσʔγϣϯؔ਺ (thunk actin) + const validateEmail = (email: string): AppThunkAction => dispatch => { + let errorMessage: string = ""; // validator Λ࢖ͬͯඞਢνΣοΫ + if (isEmpty(email)) { + errorMessage = "Email is required."; + } + if (errorMessage === "") { + dispatch(validationSuccess(“email")); // ੒ޭ࣌ + } else { + dispatch(validationFailure({ email: errorMessage })); // ࣦഊ࣌ + } + };

Slide 31

Slide 31 text

validation middleware • ൑ఆϩδοΫΛ࣮ߦ • ੒ޭɾࣦഊͦΕͧΕͷ action Λ dispatch • validationSuccess • validationFailure

Slide 32

Slide 32 text

# 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

Slide 33

Slide 33 text

# src/containers/AppContainer.tsx + const mapStateToProps = (state: AppState) => ({ + errors: state.errors + }); # src/components/App.tsx + const App: React.FC = ({ errors, onChangeEmail }) => { ~~ +

{errors.email}

display errors

Slide 34

Slide 34 text

Complete!

Slide 35

Slide 35 text

Pros • Fat component/container ͷճආ • ಠཱͨ͠ػߏͰ࣮૷ ≒ ੹຿ͷ෼཭ • ֎෦ϥΠϒϥϦ΁ͷґଘճආ • Ұͭͷػߏʹ validation Λू໿

Slide 36

Slide 36 text

Cons • Component ͔Βԕ͍ॴʹ validation ͕࣮ ૷͞ΕΔ • middleware Λ஌Βͳ͍ͱཧղ͕೉͍͠

Slide 37

Slide 37 text

Source https://github.com/kato1628/frontend-validation

Slide 38

Slide 38 text

Thank you!