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:
When I'm fetching accuracy from the object it is re-rendering 4 times and going undefined please help
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;
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.