admin管理员组

文章数量:1430077

I'm doing some testing on my UI and I've noticed that if any state changes in my redux store my ponent (shown below) re-renders and restarts with embedded video at 0. If I type in a redux-connected text field, it remounts, if a status notification hits the store, it remounts, etc.

I have no idea how to fix this and I could really use some help figuring out how to go after the bug.

tldr; How can I stop my VideoPlayer from re-rendering each time something changes in my redux store?

  • redux-toolkit
  • react

ponent

const MyComponent = () => {
...
// data used in the VideoPlayer is descructured from this variable:
const formState = useSelector(selectDynamicForm);

// renders output here in the same ponent
return (
...
 {sourceContentFound === false ? (
   <VideoPlayerDisabled />
 ) : (
   <VideoPlayerController
     title={title}
     description={description}
     sourceAddress={iframeURL}
     author={authorName}
     timeStamp={{ startTime: 0 }}
   />
 )}
)
...
}

formSlice

export const dynamicFormSlice = createSlice({
  name: 'dynamicForm',
  initialState,
  reducers: {
    updateField: (state, action) => {
      state = action.payload;
      return state;
    }
  },
});

export const selectDynamicForm = createSelector(
  (state: RootState): dynamicFormState => state.dynamicForm,
  dynamicForm => dynamicForm
);

statusHandlerSlice

I don't think this ponent does anything crazy, per-say, but I have a notification appear when the video conditions are met. When it goes back down clearStatus the video player restarts.

export const statusHandlerSlice = createSlice({
  name: 'statusHandler',
  initialState,
  reducers: {
    setStatus: (state, action: PayloadAction<IStatusObject>) => {
      const { type, display, message } = action.payload;
      state.status = {
        ...action.payload,
        message: message.charAt(0).toUpperCase() + message.slice(1),
      };
      if (display === 'internal-only' || display === 'support-both') {
        statusLogger(type, message);
      }
    },
    clearStatus: state => {
      state.status = {
        type: 'success',
        data: {},
        message: '',
        display: 'internal-only',
        key: '',
      };
    },
  },
});

export const { setStatus, clearStatus } = statusHandlerSlice.actions;

export const selectStatus = (state: RootState): IStatusObject =>
  state.statusHandler.status;

I'm doing some testing on my UI and I've noticed that if any state changes in my redux store my ponent (shown below) re-renders and restarts with embedded video at 0. If I type in a redux-connected text field, it remounts, if a status notification hits the store, it remounts, etc.

I have no idea how to fix this and I could really use some help figuring out how to go after the bug.

tldr; How can I stop my VideoPlayer from re-rendering each time something changes in my redux store?

  • redux-toolkit
  • react

ponent

const MyComponent = () => {
...
// data used in the VideoPlayer is descructured from this variable:
const formState = useSelector(selectDynamicForm);

// renders output here in the same ponent
return (
...
 {sourceContentFound === false ? (
   <VideoPlayerDisabled />
 ) : (
   <VideoPlayerController
     title={title}
     description={description}
     sourceAddress={iframeURL}
     author={authorName}
     timeStamp={{ startTime: 0 }}
   />
 )}
)
...
}

formSlice

export const dynamicFormSlice = createSlice({
  name: 'dynamicForm',
  initialState,
  reducers: {
    updateField: (state, action) => {
      state = action.payload;
      return state;
    }
  },
});

export const selectDynamicForm = createSelector(
  (state: RootState): dynamicFormState => state.dynamicForm,
  dynamicForm => dynamicForm
);

statusHandlerSlice

I don't think this ponent does anything crazy, per-say, but I have a notification appear when the video conditions are met. When it goes back down clearStatus the video player restarts.

export const statusHandlerSlice = createSlice({
  name: 'statusHandler',
  initialState,
  reducers: {
    setStatus: (state, action: PayloadAction<IStatusObject>) => {
      const { type, display, message } = action.payload;
      state.status = {
        ...action.payload,
        message: message.charAt(0).toUpperCase() + message.slice(1),
      };
      if (display === 'internal-only' || display === 'support-both') {
        statusLogger(type, message);
      }
    },
    clearStatus: state => {
      state.status = {
        type: 'success',
        data: {},
        message: '',
        display: 'internal-only',
        key: '',
      };
    },
  },
});

export const { setStatus, clearStatus } = statusHandlerSlice.actions;

export const selectStatus = (state: RootState): IStatusObject =>
  state.statusHandler.status;
Share Improve this question asked Sep 11, 2021 at 2:45 kevinkevin 3,5566 gold badges39 silver badges78 bronze badges 1
  • If you replace formState and set it with an object: const formState = {} will it still re render? Maybe it's props passed from parent that causes the re render. It is not clear why formState is needed since the code in your question never uses it. – HMR Commented Sep 11, 2021 at 7:05
Add a ment  | 

2 Answers 2

Reset to default 5

Your MyComponent is re-render every time redux store state change is because you have a selector in it

You could stop this to happen by, add an equalityFn to useSelector.

You can write your own equalityFn or use some existing function from a library that supports deep parison.

Ex: Use lodash isEqual

import { isEqual } from 'lodash';
const MyComponent = () => {
...
// data used in the VideoPlayer is descructured from this variable:
const formState = useSelector(selectDynamicForm, isEqual);

By default, useSelector use a shallow pare which can't detect deep changes inside your object, change to a deep parison function like isEqual will help you to do that, but It's not remended for all selector since there will be a performance impact.

Live Example:

  1. I suggest either creating a custom equalFn to pare the data you're using in the current ponent or do not select the whole slice, maybe some properties change is unnecessary for your ponent. like:
const { data } = useSelector(store => store.sliceA, shallowEq);

// console.log(data) => { a: "foo", b: "bar" }
// data.b is useless but once it is changed, the ponent will re-render as well

return <Typography>{data.a}</Typography>
  1. You should install React Devtools, turn on profiler, remember to check Record why each ponent rendered while profiling in setting to see what is causing re-rendering. sometimes custom hooks in libraries trigger re-rendering.

  2. whyDidYouRender is a good choice too

本文标签: javascriptAny change to redux store my causes component to rerenderStack Overflow