英文:
Redux state object getting multiple renders and going undefined
问题
Redux中调用的对象重新渲染多次并变为未定义。请帮助我?
我正在使用React和Redux制作一个打字大师工具。
“当文本输入框中提供错误输入时,它会被调用。”
为此,我创建了三个切片,如下所示:
- Test-text -- 用于输出测试文本
- Input-text -- 用于读取输入文本
- Result -- 具有三个参数的对象 { 准确性,WPM 和 WPM 平均值 }
当我从对象中获取准确性时,它重新渲染了4次并变为未定义,请帮助
- 100
- 99
- 99
- 未定义
- NaN
请查看我的代码并告诉我为什么会发生这种情况
分享我的GitHub链接:- https://github.com/vishwaTj/Typing_Master
我尝试了很多方法,但我认为这是由于 useEffect 导致的。重新渲染用于匹配输入字符串导致多次状态获取,我不确定。
结果切片的代码:
import { createSlice } from "@reduxjs/toolkit";
const ResultSlice = createSlice({
name: "Result",
initialState: {
Accuracy: 100,
WPM: 40,
WPMAverage: []
},
reducers: {
setAccuracy(state, action) {
return state.Accuracy - 1;
}
}
})
export const ResultReducer = ResultSlice.reducer;
export const { setAccuracy } = ResultSlice.actions;
输入文本切片的代码:
import { createSlice } from "@reduxjs/toolkit";
const InputTextSlice = createSlice({
name: "InputText",
initialState: "",
reducers: {
setValue(state, action) {
return action.payload;
}
}
})
export const InputTextReducer = InputTextSlice.reducer;
export const { setValue } = InputTextSlice.actions;
存储 - 索引文件的代码:
import { configureStore } from "@reduxjs/toolkit";
import { TestTextReducer } from './slices/TestText';
import { InputTextReducer } from "./slices/InputText";
import { ResultReducer } from "./slices/Result";
import { setTest } from "./slices/TestText";
import { setValue } from "./slices/InputText";
import { setAccuracy } from "./slices/Result";
const store = configureStore({
reducer: {
TestText: TestTextReducer,
InputText: InputTextReducer,
Result: ResultReducer
}
});
export { store, setTest, setValue, setAccuracy };
渲染来自Redux的状态的组件代码:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setValue, setAccuracy } from '../store';
const TextBox = () => {
const Test = useSelector((state) => {
return state.TestText;
})
const InputText = useSelector((state) => {
return state.InputText;
})
const Accuracy = useSelector((state) => {
console.log(state.Result);
return state.Result.Accuracy;
})
const dispatch = useDispatch();
const handleChange = (e) => {
dispatch(setValue(e.target.value));
}
useEffect(() => {
handleMatch();
}, [handleChange])
function handleMatch() {
if (Test === InputText) {
console.log("a complete match");
dispatch(setValue(""));
return;
}
if (Test.includes(InputText)) {
console.log("good going");
return;
}
else {
console.log(Accuracy);
dispatch(setAccuracy());
return;
}
}
return (
<div className='TextBox'>
<h2>Lesson 1</h2>
<input
type="text"
className='text-input'
value={Test}
style={{backgroundColor: "rgba(55,90,127,255)"}}/>
<input
type="text"
className='text-input user'
onChange={handleChange}
value={InputText}
/>
<div className='performance'>
<h4 className='Tags'>WPM:</h4>
<h4 className='Tags'>Accuracy:</h4>
<h4 className='Tags'>Average WPM:</h4>
</div>
</div>
)
}
export default TextBox;
英文:
Object called from Redux Re-rendering multiple times and becomes undefined. Please help me ?
I'm making a typing master tool using React and Redux.
""""" It gets called when a wrong input is given in the text input box """""
For that I created three slices as follows:
- Test-text -- To output the testing text
- Input-text -- To read the input text
- Result -- An object with three parameters { accuracy, WPM and WPMaverage }
When I'm fetching accuracy from the object it is re-rendering 4 times and going undefined please help
- 100
- 99
- 99
- undefined
- Nan
Please look at my code and let me know why is it happening
Sharing my github link :- https://github.com/vishwaTj/Typing_Master
I tried many things but I think it is due to the useEffect. The re-render used to match the input string is causing multiple state fetches I'm not sure.
Code of the slice for result:
import {createSlice} from "@reduxjs/toolkit"
const ResultSlice = createSlice({
name:"Result",
//REmember the { gap for curly brace "Oh my god"
initialState: {
Accuracy:100,
WPM:40,
WPMAverage:[]
},
reducers:{
setAccuracy(state,action){
return state.Accuracy-1;
}
}
})
export const ResultReducer = ResultSlice.reducer;
export const {setAccuracy} = ResultSlice.actions;
'''
code of slice for Input text
'''
import { createSlice } from "@reduxjs/toolkit";
const InputTextSlice = createSlice({
name:"InputText",
initialState:[],
reducers:{
setValue(State,action){
return action.payload;
}
}
})
export const InputTextReducer = InputTextSlice.reducer;
export const {setValue} = InputTextSlice.actions;
code of the Store - index file
import { configureStore } from "@reduxjs/toolkit";
import {TestTextReducer} from './slices/TestText';
import { InputTextReducer } from "./slices/InputText";
import { ResultReducer } from "./slices/Result";
import { setTest} from "./slices/TestText";
import { setValue } from "./slices/InputText";
import { setAccuracy } from "./slices/Result";
const store = configureStore({
reducer:{
TestText:TestTextReducer,
InputText:InputTextReducer,
Result:ResultReducer
}
});
export {store, setTest, setValue, setAccuracy};
code of component which is rendering the state from redux
import React, { useEffect } from 'react';
import { useDispatch,useSelector } from 'react-redux';
import { setValue,setAccuracy } from '../store';
const TextBox = () => {
const Test = useSelector((state)=>{
return state.TestText;
})
const InputText = useSelector((state)=>{
return state.InputText;
})
const Accuracy = useSelector((state)=>{
console.log(state.Result);
return state.Result.Accuracy;
})
const dispatch = useDispatch();
const handleChange=(e)=>{
dispatch(setValue(e.target.value));
}
useEffect(()=>{
handleMatch();
// eslint-disable-next-line react-hooks/exhaustive-deps
},[handleChange])
function handleMatch(){
if(Test === InputText){
console.log( "a cmoplete match");
dispatch(setValue(""));
return;
}
if(Test.includes(InputText)){
console.log("good going");
return;
}
else{
console.log(Accuracy);
dispatch(setAccuracy());
return;
}
}
return (
<div className='TextBox'>
<h2>Lesson 1</h2>
<input
type="text"
className='text-input'
value={Test}
style={{backgroundColor:"rgba(55,90,127,255)"}}/>
<input
type="Text"
className='text-input user'
onChange={handleChange}
value={InputText}
/>
<div className='performance'>
<h4 className='Tags'>WPM:</h4>
<h4 className='Tags'>Accuracy:</h4>
<h4 className='Tags'>Average WPM:</h4>
</div>
</div>
)
}
export default TextBox;
答案1
得分: 0
根据TextBox.js:16
上的控制台日志,似乎是在记录选定的state.Result
状态,某处将状态从对象更改为数字。一旦发生这种情况,并且调用了额外的dispatch(setAccuracy());
,setAccuracy
reducer 案例会尝试从数字的未定义属性中减去1。对非数字的数学操作往往会在最坏的情况下生成异常,在最好的情况下生成NaN
。
setAccuracy
reducer 函数仅返回state.Accuracy - 1
。Redux-Toolkit reducer 函数应该要么修改草稿状态,要么返回下一个状态...所有的状态。
示例:
const ResultSlice = createSlice({
name: "Result",
initialState: {
Accuracy: 100,
WPM: 40,
WPMAverage: []
},
reducers: {
setAccuracy(state) {
state.Accuracy = state.Accuracy - 1;
}
}
});
或者
const ResultSlice = createSlice({
name: "Result",
initialState: {
Accuracy: 100,
WPM: 40,
WPMAverage: []
},
reducers: {
setAccuracy(state) {
return {
...state,
Accuracy: state.Accuracy - 1;
};
}
}
});
第二种方法可行,但第一种方法更受欢迎,因为RTK在底层实现了immer.js,允许您编写简洁的、可变的状态更新。换句话说,它允许您编写更少的代码,更清晰、更易读和更易维护。请参阅使用 Immer 编写 Reducer。
英文:
Based on the console log on TextBox.js:16
, which it seems is logging the selected state.Result
state that somewhere the state is mutated from an object to a number. Once this happens and an additional dispatch(setAccuracy());
is called, the setAccuracy
reducer case attemps to subtract 1 from an undefined property of a number. Mathematical operations on non-numbers tend to generate exceptions at worst, and NaN
at best.
The setAccuracy
reducer function is only returning state.Accuracy - 1
. Redux-Toolkit reducer functions should either mutate the draft state or return the next state... all of it.
Examples:
const ResultSlice = createSlice({
name: "Result",
initialState: {
Accuracy: 100,
WPM: 40,
WPMAverage: []
},
reducers: {
setAccuracy(state) {
state.Accuracy = state.Accuracy - 1;
}
}
});
or
const ResultSlice = createSlice({
name: "Result",
initialState: {
Accuracy: 100,
WPM: 40,
WPMAverage: []
},
reducers: {
setAccuracy(state) {
return {
...state,
Accuracy: state.Accuracy - 1;
};
}
}
});
The second method will work, but the first method is preferred since RTK implements immer.js under the hood and allows you to write succinct, mutable state updates. In other words, it allows you to write less code that is more clean and easier to read and maintain. See Writing Reducers with Immer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论