SM1105922
SM1105922

Reputation: 127

Not able to update state value with use reducer

I am trying to update the input fields values to state using the react context and reducer but I am not able to update the state. Request help with the same.

State function:

  const handleChangeFor = input => e => {
    {
      dispatch({
        type: UPDATE_FIELD,
        payload: { input, e }
      });
    }
  };

Reducer :

    case UPDATE_FIELD:
      return {
        ...state,
        [action.payload.input]: action.payload.value
      };


Component :

        <InputTextContainer>
          <InputSelect
            value={addOnCategory}
            name="addOnCategory"
            onChange={handleChangeFor('addOnCategory')}
          >
            <InputOption value="" style={{ display: 'none' }}>
              Please select
            </InputOption>
            <InputOption>Add On</InputOption>
            <InputOption>Flavours</InputOption>
          </InputSelect>
        </InputTextContainer>

Upvotes: 1

Views: 560

Answers (1)

HMR
HMR

Reputation: 39270

There are 2 things wrong with your code:

  1. action.payload.value does not exist, it is action.payload.e.value
  2. You cannot use the event in the reducer or you'll get an error that synthetic event will be reused, use the event value in the action instead
  3. An action creator should only create an object, dispatch it in the component.

const UPDATE_FIELD = 'UPDATE_FIELD';
const reducer = (state, { type, payload }) => {
  if (type === UPDATE_FIELD) {
    const { input, value } = payload;
    return { ...state, [input]: value };
  }
};
const handleChangeFor = (input, e) => {
  //event will be re used and cause an error
  //  use value instead of passing event to
  //  reducer
  return {
    type: UPDATE_FIELD,
    payload: { input, value: e.target.value },
  };
};
const PureInput = React.memo(function PureInput({
  value,
  onChange,
}) {
  const r = React.useRef(0);
  r.current++;
  return (
    <label>
      pure input rendered: {r.current} times
      <input
        type="text"
        onChange={onChange('pure')}
        value={value}
      />
    </label>
  );
});
const App = () => {
  const [state, dispatch] = React.useReducer(reducer, {
    name: '',
    pure: '',
  });
  //if you want to optimize you can use useCallback
  const handleChange = React.useCallback(
    (input) => (e) => dispatch(handleChangeFor(input, e)),
    []
  );

  return (
    <div>
      <div>
        <input
          type="text"
          onChange={(e) =>
            dispatch(handleChangeFor('name', e))
          }
          value={state['name']}
        />
      </div>
      <PureInput
        value={state['pure']}
        onChange={handleChange}
      />
    </div>
  );
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions