derty14
derty14

Reputation: 115

Problem with filling input and communication problem with redux in React

There is a base that contains text from inputs:

let data={
  textInput:"",
  inputInfo:{size:""},
};
export const loginReducer=(state=data,action)=>{
    switch (action.type) {
        case "ChangeInputInfoSize":
          if (Number(action.size)|| action.size==="" ){
            let Statecopy={...state};
            Statecopy.inputInfo.size=action.size;
            return {...Statecopy};
          }else {
            return state
        }
        default:
                return state;
    }
}
export const ChangeInputInfoSizeAC=(size)=>({
    type:"ChangeInputInfoSize",
    size
});

As well as the component and its container:

import React from "react"
import {connect} from "react-redux";
import {DataFilling} from "./DataFilling";
import {ChangeInputInfoSizeAC} from "../store/loginReducer";
let MapStateToProps=(state)=>{
    return {
        inputInfo:state.loginReducer.inputInfo,
        textInput:state.loginReducer.textInput
    }
};
export const DataFillingContainer=connect(MapStateToProps,{ChangeInputInfoSizeAC})(DataFilling)

Component:

import React from "react"
export let DataFilling = (props) => {
    let ChangeInputInfoSizeFunc = (e) => {
        props.ChangeInputInfoSizeAC(e.target.value)
    };
<input placeholder="size" value={props.inputInfo.size} onChange={ChangeInputInfoSizeFunc} />
    }

When you try to fill the field, there is no change in the field, but if you replace inputInfo.size with textInput everywhere, then everything will work. What needs to be changed in the first option for it to work?

Upvotes: 0

Views: 41

Answers (2)

Makan
Makan

Reputation: 719

I guess problem is in reducer where creating Statecopy

            let Statecopy={...state};
            Statecopy.inputInfo.size=action.size;

In first line let Statecopy={...state} will create a new object {textInput, inputInfo} but in second line Statecopy.inputInfo actually referencing to the old inputInfo, so it overwrite size in old inputInfo and keep its reference unchanged.

I recommend make states flat as far as possible or make sure creating new state.

let Statecopy={...state,inputInfo:{size:action.size}};

In addition, you can do few improvement to your code by following these steps:

  1. Camel case naming is Javascript convention, so instead of let Statecopy write let stateCopy

  2. Dispatch type convention is uppercase separated with underlines, so instead of "ChangeInputInfoSize" write "CHANGE_INPUT_INFO_SIZE"

  3. When declaring a function use const because you don't want accidentally overwrite a function, so const ChangeInputInfoSizeFunc = (e) => {... is correct. This is true for export const DataFilling as well.

  4. For a controlled component like DataFilling only dispatch the final state, so onChange event will save value in a local state, then an onBlur event dispatch the result to reducer.

  5. Limit declaring new variables as far as possible, so in reducer you don't need stateCopy,

  6. Make reducer initial state a const variable, you don't want overwrite it.

  7. in if (Number(action.size)|| action.size==="" ) first part will be a number but second part will be an empty string. Because of consistency and preventing future bugs make both same. Also you can do this validation before dispatching size to the reducer.

Hopefully, all these recommendations will help to avoid future bugs

Upvotes: 1

derty14
derty14

Reputation: 115

I had to do deep copy

 case "ChangeInputInfoSize":{
        if (Number(action.size)|| action.size==="" ){
            let copyState = {...state};
            copyState.inputInfo = {...state.inputInfo};
            copyState.inputInfo.size=action.size
            return {...copyState};
        }else {
            return state
        }
    }

Upvotes: 0

Related Questions