Skip to content Skip to sidebar Skip to footer

Use Of React GetDerivedStateFromProps()

I'm exploring React and am somewhat confused over lifecycle methods and parent-child communication. Specifically, I'm trying to create a component which wraps a select element and

Solution 1:

You can simplify by not having SelectOther have any state, here is an example of how you can pass a function that dispatches an action to change values. Because SelectOther is a pure component it won't needlessly re render:

//make this a pure component so it won't re render
const SelectOther = React.memo(function SelectOther({
  label,
  name,
  value,
  options,
  handleChange,
}) {
  console.log('in render',name, value);
  const showInput = !options
    .map(o => o.value)
    .includes(value);
  return (
    <div>
      <label>{label}</label>
      <select
        name={name}
        value={showInput ? '' : value}
        onChange={handleChange}
      >
        {options.map(option => (
          <option key={option.value} value={option.value}>
            {option.label}
          </option>
        ))}
        <option value="">Other</option>
      </select>
      {showInput && (
        <div>
          <label>{label} (specify other)</label>
          <input
            type="text"
            name={name}
            className="form-control"
            value={value}
            onChange={handleChange}
          ></input>
        </div>
      )}
    </div>
  );
});

const App = () => {
  //create options once during App life cycle
  const options = React.useMemo(
    () => [
      { value: 'one', label: 'one label' },
      { value: 'two', label: 'two label' },
    ],
    []
  );
  //create a state to hold input values and provide
  //  a reducer to create new state based on actions
  const [state, dispatch] = React.useReducer(
    (state, { type, payload }) => {
      //if type of action is change then change the
      //  payload.name field to payload.value
      if (type === 'CHANGE') {
        const { name, value } = payload;
        return { ...state, [name]: value };
      }
      return state;
    },
    //initial state for the inputs
    {
      my_name: '',
      other_input: options[0].value,
    }
  );
  //use React.useCallback to create a callback
  //  function that doesn't change. This would be
  //  harder if you used useState instead of useReducer
  const handleChange = React.useCallback(
    ({ target: { name, value } }) => {
      dispatch({
        type: 'CHANGE',
        payload: {
          name,
          value,
        },
      });
    },
    []
  );
  return (
    <div>
      <SelectOther
        label="label"
        name="my_name"
        value={state.my_name}
        options={options}
        handleChange={handleChange}
      />
      <SelectOther
        label="other"
        name="other_input"
        value={state.other_input}
        options={options}
        handleChange={handleChange}
      />
    </div>
  );
};


//render app
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>

I could have uses useState in App but then I have to use useEventCallback or do a useState for every input value. The following documentation comes up with the useEventCallback pattern and then immediately after states that we don’t recommend this pattern so that's why I came up with the useReducer solution instead.


Post a Comment for "Use Of React GetDerivedStateFromProps()"