React reduxを使った状態管理の練習としてツイッター風アプリを作成していた際に、reducer経由でdeleteしてるのに画面の再レンダリングが走らない問題に遭遇。
きっとレンダリング発生条件周りの理解が甘いのだと思い、見直してみたものの修正できずに困っていたのですが、実はAPIのdeleteメソッドの挙動の理解不足だったことがわかりました。
基本中の基本すぎてお恥ずかしい限りですが、一応記録として。
apiにdeleteメソッドを投げた時の返り値
getメソッドやpostメソッドだと返ってくる値がわかりやすいですが、deleteメソッドは上の結果を見るとわかるように、空っぽのオブジェクトが返ってくる。
なので、例えば下のような実装をするとまずいわけです。
const tweetSlice = createSlice({
name: "tweet",
initialState: initState,
reducers:{
destroy(state, {type, payload}){
const newState = [...state];
return newState.filter( (tweet)=>{
return tweet.id !== payload.id
} );
}
}
});
const { destroy } = tweetSlice.actions;
// 非同期処理部分
const ENDPOINT_URL = "http://localhost:3000/tweets";
const asyncDestroyTweet = (payload) => {
return( async(dispatch, getState)=>{
const result = await.delete(ENDPOINT_URL + "/" + payload.id);
dispatch( destroy(result.data) );
} );
};
export { asyncDestroyTweet };
export default tweetSlice.reducer;
まずい部分はここ。
const result = await.delete(ENDPOINT_URL + "/" + payload.id);
dispatch( destroy(result.data) );
resultは空っぽなのに、それをdestroy関数に入れても当然何も起きないので、結果storeの更新が行われず、画面のレンダリングも行われない。
正しい実装
正しくは、以下のようにすること。
await axios.delete(ENDPOINT_URL + "/" + payload.id);
dispatch( destroy(payload) );
無意識でGETとかPOSTとかと同じように書いていていると引っ掛かるかも。
気づいたら当たり前のことなんですが、しばらく気づけなかった、、、