user14216898
user14216898

Reputation:

How to handle multiple input values in redux?

I'm making a todo app with react-redux now. For now, I have 4 inputs and want to combine each input value into one and manage it with react-redux. But I keep failing. In this case, What should I do?

The data structure I want to make is like this.

const initialState = {
  list: [
    {
      id: 0,
      dateData: "",
      timeData: "",
      title: "",
      desc: "",
    },
  ]
};

reducer :

export const setDate = value => ({
  type: SET_DATE_DATA,
  payload: {
    value
  },
})

export const setTime = value => ({
  type: SET_TIME_DATA,
  payload: {
    value
  },
})

export const setTitle = value => ({
  type: SET_TITLE,
  payload: {
    value
  },
})

export const setDesc = value => ({
  type: SET_DESC,
  payload: {
    value
  },
})

const initialState = {
  list: [],
}

export default function todoReducer (state=initialState, action) {
  switch (action.type) {
    case SET_DATE_DATA:
      return {
        ...state,
        list: state.list.concat({
          dateData: action.payload.value,
        }),
      };
    case SET_TIME_DATA:
      return {
        ...state,
        list: state.list.concat({
          timeData: action.payload.value,
        }),
      };
    case SET_TITLE:
      return {
        ...state,
        list: state.list.concat({
          title: action.payload.value,
        }),
      };
    case SET_DESC:
      return {
        ...state,
        list: state.list.concat({
          desc: action.payload.value,
        }),
      };
  }
}

TodoContainer : This logic is passed to the todo component and used as the onChange prop of the input.


  const setInput = (e) => {
    const { name, value } = e.target
    switch (name) {
      case "todo-date":
        return alarmActions.setDate(value);
      case "todo-time":
        return alarmActions.setTime(value);
      case "todo-title":
        return alarmActions.setTitle(value);
      case "todo-desc":
        return alarmActions.setDesc(value);
    }
  }

Upvotes: 0

Views: 1169

Answers (2)

Linda Paiste
Linda Paiste

Reputation: 42288

The primary bug in your current code is that you are using “concat” which adds a new item to the end of the array. Each time one of your actions is dispatched, you are adding a new item to the list which has only the changed property rather than updating the existing item.

You need to find the currently editing item and update it (I find this easier if using an object keyed by id rather than an array). You need to know which object you are updating, which means that you either need to include the item id in your action payload or you need to store the id of the current item somewhere in your state (I recommend passing it through payload).

Prateek raises a valid point that you may want your EditingItem component to get the existing/initial value from the redux state, store the changes in component state, and then only dispatch to redux when the user clicks the Submit button.

Upvotes: 1

Prateek Thapa
Prateek Thapa

Reputation: 4938

Keep your form state local using React.useState and upon submitting the form set the whole data to your redux.

You wouldn't wanna render all your component if your input field change. When one of your inputs change, the Form component re-renders, upon handling the form, the redux state gets updated.

function reducer(action) {
  if (action.type === "SET_FORM_DATA") {
    return { ...state, list: state.list.concat(action.value) };
  }
}

function setFormData(form) {
  return {
    type: "SET_FORM_DATA",
    payload: {
      value: form
    }
  };
}

function MyForm() {
  const [formState, setFormState] = React.useState({
    dateData: "",
    timeData: "",
    title: "",
    desc: ""
  });

  function handleSubmit() {
    reduxActions.setFormData(formState);
  }


   function handleInputChange(e) {
    setFormState({
      ...formState,
      [e.target.name]: e.target.value
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input 
       type="text" 
       name="title" 
       value={formState.title} 
       onChange={handleInputChange} 
      />
      {...rest of your inputs}
    </form>
  );
}

Upvotes: 2

Related Questions