更新 Redux 存储中的状态变量会导致整个应用程序不必要的重新渲染

问题描述 投票:0回答:1

我正在尝试通过一个项目来学习 redux-toolkit。

我在商店内使用“toEditPostId”变量(初始值为空)来获取我要编辑的帖子的 id,当我将其值设置为 id 字符串时,应用程序工作正常,但是当我单击清除时我的表单组件中的按钮调用“dispatch(setToEditPostId(null))”,然后整个应用程序重新渲染并自动调用“handleSubmit”函数,然后添加一个新的空帖子,这是我不希望发生的.

我在导致问题的片段附近添加了“****************”。

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axiosInstance  from "../utils/axiosInstance";

export const fetchMemoryPosts = createAsyncThunk('posts/fetchPosts', async (_, thunkApi)=>{

  try {
    const response = await axiosInstance.get('/posts');
    return response.data.posts;
  } catch (error) {
    const errorMessage = error.response.data.match(/Error: (.*?)<br>/)[1];
    const errorCode = error.response.status;
    return thunkApi.rejectWithValue({errorMessage,errorCode});
  }
});

export const createMemoryPost = createAsyncThunk('posts/createPosts', async(data, thunkApi)=>{

  const tagsArr = data.tags.split(',').map((ele)=> ele.trim());
  const preparedData = {...data, tags: tagsArr};

  try {
    const response = await axiosInstance.post('/posts/create', preparedData);
    return response.data.data;
  } catch (error) {
    const errorMessage = error.response.data.match(/Error: (.*?)<br>/)[1];
    const errorCode = error.response.status
    return thunkApi.rejectWithValue({errorMessage, errorCode})
  }
})

const initialState = {
  posts: [],
  status: 'idle',
  error: null,
  toEditPostId: null, //The state variable to track the id of the post to edit*************
}

const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {     // changing the value to an id and back to null here***********************
    setToEditPostId(state,action){
      state.toEditPostId = action.payload;
    }
  },
  extraReducers(builder){
    builder
    .addCase(fetchMemoryPosts.pending, (state,_)=>{
      state.status = 'loading';
    })
    .addCase(fetchMemoryPosts.fulfilled, (state, action)=>{
      state.status = 'success';
      state.posts = action.payload;
    })
    .addCase(fetchMemoryPosts.rejected, (state, action)=>{
      state.status = 'failure';
      state.error = action.payload;
    })
    .addCase(createMemoryPost.fulfilled, (state, action)=>{
      state.status = 'success';
      state.posts = state.posts.concat(action.payload);
    })
    .addCase(createMemoryPost.rejected, (state, action)=>{
      state.status = 'failure';
      state.error = action.payload;
    })
  }
});

export const getAllPostsSelector = (state) => state.posts.posts;
export const getPostsErrorSelector = (state) => state.posts.error;
export const getPostsStatusSelector = (state) => state.posts.status;
export const getToEditPostIdSelector = (state) => state.posts.toEditPostId;


export const { setToEditPostId } = postsSlice.actions;


export default postsSlice.reducer;

下面是Form组件。

import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createMemoryPost, setToEditPostId, getToEditPostIdSelector, getAllPostsSelector } from '../../features/postsSlice';

const Form = () => {
  const dispatch = useDispatch();

  const allPosts = useSelector(getAllPostsSelector);
  const postId = useSelector(getToEditPostIdSelector);

  let targetPost;
  if(postId){
    targetPost = allPosts.filter((post) => post._id === postId);
  }

  console.log("pi->", postId)
  console.log("po->", targetPost);


  const initialPostDataState = {
    creator: '', title: '', message:'', tags:''
  }

  const [postData, setPostData] = useState(initialPostDataState);

  // Below function runs unnecessarily when the dispatch(setToEditPostId(null)) is called********************************* 
  const handleSubmit =(e)=>{
    console.log("it ran");
    e.preventDefault()
    dispatch(createMemoryPost(postData));

    setPostData(initialPostDataState);
  }


  const handleInput =(e)=>{
    setPostData({...postData, [e.target.name]: e.target.value})
  }

  const clearForm = ()=>{
    dispatch(setToEditPostId(null))
    setPostData(initialPostDataState);
  }

  return (
    <main className='bg-transparent_bg w-full flex'>
      <form className='w-full text-center space-y-3 p-2 box-border' 
        onSubmit={handleSubmit}
      >
        <h3
         className='font-extrabold '
        >
          {postId !== null? "" : "Create a memory"}
        </h3>
        <input 
          className='input'
          type="text" 
          placeholder='Creator' 
          name='creator'
          value={postData.creator}
          onChange={handleInput}
        />
        <input 
          className='input'
          type="text" 
          placeholder='Title' 
          name='title'
          value={postData.title}
          onChange={handleInput}
        />
        <textarea 
          className='input'
          placeholder='Message'
          name="message"
          cols="30" 
          rows="5"
          value={postData.message}
          onChange={handleInput}
        />
        <input 
          className='input'
          type="text" 
          placeholder='Tags (coma seperated)' 
          name='tags'
          value={postData.tags}
          onChange={handleInput}
        />

        <div className='flex justify-around py-1 box-border'>
          <button
            type='submit'
            className='bg-blue-400 w-24'
          >
            Submit
          </button>
          <button // clear button to call dispatch to set value to null *********************
            onClick={()=>dispatch(setToEditPostId(null))}
            className='bg-red-500 w-24'
          >
            Clear
          </button>
        </div>
      </form>
    </main>
  )
}

export default Form;

javascript reactjs redux-toolkit
1个回答
0
投票
如果您没有

显式

指定按钮类型,则
button
元素默认具有type="submit"

按钮类型属性:

type

按钮的默认行为。可能的值为:

  • submit
    :该按钮将表单数据提交到服务器。 如果未为关联按钮指定属性,则这是默认值 带有
    <form>
    ,或者属性为空或无效值
  • reset
    :该按钮将所有控件重置为其初始值,如
    <input type="reset">
    。 (这种行为往往会惹恼用户。)
  • button
    :该按钮没有默认行为,默认情况下按下时不会执行任何操作。它可以让客户端脚本监听 元素的事件,当事件发生时触发。

toEditPostId
状态“清除”回 null 的第二个按钮也是提交表单。指定“清除”按钮 不是
"submit"
类型按钮。

<button
  type='submit'
  className='bg-blue-400 w-24'
>
  Submit
</button>
<button
  type="button" // <-- non-submit type button
  onClick={() => dispatch(setToEditPostId(null))}
  className='bg-red-500 w-24'
>
  Clear
</button>
© www.soinside.com 2019 - 2024. All rights reserved.