Kontynuacja lekcji poprzedniej, funkcja reducer w TypeScript, przyda się nam to do Reacta. Tym razem ogarniamy opcjonaly payload. Do dzieła!
Ok, przypomnijmy sobie poprzednią funkcję reducer:
const initState = {count: 0};
const enum REDUCER_ACTION_TYPE {
INCREMENT,
DECREMENT
};
type ReducerAction = {
type: REDUCER_ACTION_TYPE
};
const reducer = (state: typeof initState, action: ReducerAction): typeof initState => {
switch (action.type) {
case REDUCER_ACTION_TYPE.INCREMENT:
return { ...state, count: state.count + 1 }
case REDUCER_ACTION_TYPE.DECREMENT:
return { ...state, count: state.count - 1 }
default:
throw new Error()
}
}
Ok, teraz nasz initState będzie nieco bardziej zaawansowany:
const initState = { count: 0, text: '' }
Enum na typy akcji:
const enum REDUCER_ACTION_TYPE {
INCREMENT,
DECREMENT,
NEW_INPUT,
}
Typ akcji, z opcjonalnym payloadem określonego typu:
type ReducerAction = {
type: REDUCER_ACTION_TYPE,
payload?: string,
}
Piszemy sygnaturę reducera:
const reducer = (state: typeof initState, action: ReducerAction): typeof initState => {
switch (action.type) {
//(...)
}
}
Jak wszystko jasne, to kontynuujemy:
const reducer = (state: typeof initState, action: ReducerAction): typeof initState => {
switch (action.type) {
case REDUCER_ACTION_TYPE.INCREMENT:
return { ...state, count: state.count + 1 }
case REDUCER_ACTION_TYPE.DECREMENT:
return { ...state, count: state.count - 1 }
case REDUCER_ACTION_TYPE.NEW_INPUT:
//(...)
default:
throw new Error()
}
}
Teraz, gdy nasz stan ma inne pola niż tylko count, widzimy po co nam ten spread. Bo mutować stanu nie możemy, musimy zwrócić nowy stan. Ale nie wszystkie pola chcemy nadpisać, w przypadku akcji powyżej tylko count ma być nadpisany (o wartość -1 lub +1).
Ok, pomyślmy jak załatwić new input. Już się chyba domyślamy, że trzeba go zastąpić payloadem:
case REDUCER_ACTION_TYPE.NEW_INPUT:
return { ...state, text: action.payload }
//Type 'string | undefined' is not assignable to type 'string'.
No właśnie, payload może być opcjonalny. Zaś obiekt musi mieć string pod kluczem text. Jak to rozwiązać? Dość łatwo:
case REDUCER_ACTION_TYPE.NEW_INPUT:
return { ...state, text: action.payload ?? "" }
//ok
Te operatory już powinniśmy znać na tym poziomie. Cała funkcja:
const reducer = (state: typeof initState, action: ReducerAction): typeof initState => {
switch (action.type) {
case REDUCER_ACTION_TYPE.INCREMENT:
return { ...state, count: state.count + 1 }
case REDUCER_ACTION_TYPE.DECREMENT:
return { ...state, count: state.count - 1 }
case REDUCER_ACTION_TYPE.NEW_INPUT:
return { ...state, text: action.payload ?? "" }
//ok
default:
throw new Error()
}
}
Ok, jeżeli to ogarniamy, to w następnej lekcji połączymy to z Reactem. Do następnego razu!