ある日
お勉強用react製web appをいじっていたら TypeError: _useSelector is undefined
というエラーが!
しかし普通にbuildは通る そしてググっても出てこない(気がする)
↓ばーじょん↓
react@16.12.0
react-redux@7.1.3
redux@4.0.5
reselect@4.0.0
こんなコード書いてた
// src/containers/App.tsx
const appSelector = createSelector(
(state: { init: AppState }) => state.init,
init => init
)
export const AppContainer: React.FC = () => {
const dispatch = useDispatch()
const { loading, loaded, error } = useSelector(appSelector)
const loadDispatcher = (): void => {
dispatch(initOp())
}
return (
<AppView
loading={loading}
loaded={loaded}
error={error}
loadDispatcher={loadDispatcher}
/>
)
}
// src/reducers/index.ts
export default combineReducers({
app: appReducer,
todos: todoReducer,
visibilityFilter: visibilityFilterReducer,
})
// src/reducers/app.ts
export const appReducer = reducerWithInitialState({
loaded: false,
loading: false,
error: null,
} as AppState)
.cases(...
と、こうやって書けば一目瞭然で(実際はファイルが別れているのでそこそこ時間を取られた)
-
appSelector()
ではinit
からAppState
を取得しようとしている -
combineReducers()
ではapp
にappReducer
として結合されている
このため、上記エラーが出たようだった。
実際にはuseSelector()
の引数にダミーの(() => true
的な)selectorを使うなどしてエラー原因の特定を行った。
以上よりappSelectorを以下のように修正することでエラーは解消した。
// reselect使っている理由は特に無いです(使ってみたかった)
// この程度ならワンライナーで
// const appSelector = ({ app }: { app: AppState }): AppState => app
// の方が分かりやすいですね
const appSelector = createSelector(
(state: { app: AppState }) => state.app,
app => app
)
所感
reducerが無いと_useSelector()
が未定義状態になるのかーというのが一番の収穫
当初InitState
として定義していたが名前的に微妙だな思いAppStateに変えたのだが、この修正が一部漏れていた
selector周りでtypescriptの型チェックが微妙な感じになってしまうのは予想外で、もう少し丁寧に書くべきだったと反省