在输入更改事件上使用调度会导致重新呈现整个页面 - Redux Toolkit
Using dispatch on input change event causes rerendering the whole page - Redux Toolkit
我是 React 和 Redux 的新手,我遇到了这个问题:
我正在使用 Redux 工具包。我已经对无线电输入进行了样式,当检查一个人时,它必须更改具有其值的全局状态,但在全局状态更改时不得重新启动,因为在rerender上,它会破坏样式(CSS :checked
选择器的作品。不当)。只有使用该状态的元素必须改变,即。按钮。当全局状态发生变化时,如何防止它们重新渲染?我究竟做错了什么?提前致谢。
const dispatch = useDispatch()
const { regType } = useSelector((state) => state.regTypes)
const handleChange = (e) => {
dispatch(changeRegType(e.target.value))
}
return (
<form>
<StyledRadio name="registrationType" id="private" value="private" onChange={handleChange} >
<StyledRadio name="registrationType" id="company" value="company" onChange={handleChange} />
<Button type="submit" disabled={!!regType ? true : false}>Next</Button>
</form>
)
切片
export const registrationTypesSlice = createSlice({
name: "registrationType",
initialState: {
regType: "",
},
reducers: {
changeRegType: (state, action) => {
state.regType = action.payload
},
},
})
export const { changeRegType } = registrationTypesSlice.actions
export default registrationTypesSlice.reducer
简短回答:您需要使用 React.memo HOC wrap your StyledRadio
component. And, use useCallback 挂钩创建 handleChange
事件处理程序的记忆版本。
答案很长,请看下面的代码:
index.tsx
:
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { StyledRadio } from './StyledRadio';
const changeRegType = (v) => ({ type: 'CHANGE_REG_TYPE', payload: v });
export function Comp() {
const dispatch = useDispatch();
const { regType } = useSelector((state: any) => state.regTypes);
console.log('regType: ', regType);
const handleChange = useCallback(
(e) => {
const { value } = e.target;
dispatch(changeRegType(value));
},
[dispatch],
);
return (
<form>
<StyledRadio name="registrationType" data-testid="private" id="private" value="private" onChange={handleChange} />
<StyledRadio name="registrationType" data-testid="company" id="company" value="company" onChange={handleChange} />
<button type="submit" disabled={!!regType ? true : false}>
Next
</button>
</form>
);
}
StyledRadio.tsx
:
import React from 'react';
export const StyledRadio = React.memo((props: React.ComponentPropsWithoutRef<'input'>) => {
console.count('StyledRadio render');
return <input {...props} type="radio" />;
});
index.test.tsx
:
import { configureStore } from '@reduxjs/toolkit';
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Comp } from './';
const store = configureStore({
reducer: (state = { regTypes: { regType: '' } }, action) => {
switch (action.type) {
case 'CHANGE_REG_TYPE':
return { ...state, regTypes: { regType: action.payload } };
default:
return state;
}
},
});
describe('71504950', () => {
test('should pass', () => {
render(
<Provider store={store}>
<Comp />
</Provider>,
);
fireEvent.click(screen.getByTestId('private'), { target: { value: 'private' } });
});
});
测试结果:
PASS redux-toolkit-example packages/redux-toolkit-example/Whosebug/71504950/index.test.tsx
71504950
✓ should pass (56 ms)
console.log
regType:
at Comp (packages/redux-toolkit-example/Whosebug/71504950/index.tsx:10:11)
console.count
StyledRadio render: 1
at packages/redux-toolkit-example/Whosebug/71504950/StyledRadio.tsx:4:11
console.count
StyledRadio render: 2
at packages/redux-toolkit-example/Whosebug/71504950/StyledRadio.tsx:4:11
console.log
regType: private
at Comp (packages/redux-toolkit-example/Whosebug/71504950/index.tsx:10:11)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.303 s
如您所见,当 Comp
组件首次呈现日志时:
// first render
regType:
StyledRadio render: 1
StyledRadio render: 2
// second render
regType: private
触发radio change事件后,通过CHANGE_REG_TYPE
动作改变state
。 Comp
会re-render,此时StyledRadio
的props和之前render一样,所以React.memo
会跳过re-render组件.
如果删除 useCallback
或 React.memo
,您将获得日志:
// first render
regType:
StyledRadio render: 1
StyledRadio render: 2
// second render
regType: private
StyledRadio render: 3
StyledRadio render: 4
我是 React 和 Redux 的新手,我遇到了这个问题:
我正在使用 Redux 工具包。我已经对无线电输入进行了样式,当检查一个人时,它必须更改具有其值的全局状态,但在全局状态更改时不得重新启动,因为在rerender上,它会破坏样式(CSS :checked
选择器的作品。不当)。只有使用该状态的元素必须改变,即。按钮。当全局状态发生变化时,如何防止它们重新渲染?我究竟做错了什么?提前致谢。
const dispatch = useDispatch()
const { regType } = useSelector((state) => state.regTypes)
const handleChange = (e) => {
dispatch(changeRegType(e.target.value))
}
return (
<form>
<StyledRadio name="registrationType" id="private" value="private" onChange={handleChange} >
<StyledRadio name="registrationType" id="company" value="company" onChange={handleChange} />
<Button type="submit" disabled={!!regType ? true : false}>Next</Button>
</form>
)
切片
export const registrationTypesSlice = createSlice({
name: "registrationType",
initialState: {
regType: "",
},
reducers: {
changeRegType: (state, action) => {
state.regType = action.payload
},
},
})
export const { changeRegType } = registrationTypesSlice.actions
export default registrationTypesSlice.reducer
简短回答:您需要使用 React.memo HOC wrap your StyledRadio
component. And, use useCallback 挂钩创建 handleChange
事件处理程序的记忆版本。
答案很长,请看下面的代码:
index.tsx
:
import React, { useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { StyledRadio } from './StyledRadio';
const changeRegType = (v) => ({ type: 'CHANGE_REG_TYPE', payload: v });
export function Comp() {
const dispatch = useDispatch();
const { regType } = useSelector((state: any) => state.regTypes);
console.log('regType: ', regType);
const handleChange = useCallback(
(e) => {
const { value } = e.target;
dispatch(changeRegType(value));
},
[dispatch],
);
return (
<form>
<StyledRadio name="registrationType" data-testid="private" id="private" value="private" onChange={handleChange} />
<StyledRadio name="registrationType" data-testid="company" id="company" value="company" onChange={handleChange} />
<button type="submit" disabled={!!regType ? true : false}>
Next
</button>
</form>
);
}
StyledRadio.tsx
:
import React from 'react';
export const StyledRadio = React.memo((props: React.ComponentPropsWithoutRef<'input'>) => {
console.count('StyledRadio render');
return <input {...props} type="radio" />;
});
index.test.tsx
:
import { configureStore } from '@reduxjs/toolkit';
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { Provider } from 'react-redux';
import { Comp } from './';
const store = configureStore({
reducer: (state = { regTypes: { regType: '' } }, action) => {
switch (action.type) {
case 'CHANGE_REG_TYPE':
return { ...state, regTypes: { regType: action.payload } };
default:
return state;
}
},
});
describe('71504950', () => {
test('should pass', () => {
render(
<Provider store={store}>
<Comp />
</Provider>,
);
fireEvent.click(screen.getByTestId('private'), { target: { value: 'private' } });
});
});
测试结果:
PASS redux-toolkit-example packages/redux-toolkit-example/Whosebug/71504950/index.test.tsx
71504950
✓ should pass (56 ms)
console.log
regType:
at Comp (packages/redux-toolkit-example/Whosebug/71504950/index.tsx:10:11)
console.count
StyledRadio render: 1
at packages/redux-toolkit-example/Whosebug/71504950/StyledRadio.tsx:4:11
console.count
StyledRadio render: 2
at packages/redux-toolkit-example/Whosebug/71504950/StyledRadio.tsx:4:11
console.log
regType: private
at Comp (packages/redux-toolkit-example/Whosebug/71504950/index.tsx:10:11)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.303 s
如您所见,当 Comp
组件首次呈现日志时:
// first render
regType:
StyledRadio render: 1
StyledRadio render: 2
// second render
regType: private
触发radio change事件后,通过CHANGE_REG_TYPE
动作改变state
。 Comp
会re-render,此时StyledRadio
的props和之前render一样,所以React.memo
会跳过re-render组件.
如果删除 useCallback
或 React.memo
,您将获得日志:
// first render
regType:
StyledRadio render: 1
StyledRadio render: 2
// second render
regType: private
StyledRadio render: 3
StyledRadio render: 4