小能豆

Condition operator, doesn't react on condition changes, I guess

javascript

I have a React component representing a form with inputs (Text, Number, Date). The date input has a default value - today. I use this component for two functions: creating an object and editing an object. In the first case, all inputs are empty by default, except for the date input, which is set to today. In the second case, the inputs receive default values from optional props (values) that are passed to the component from the parent component’s state. The component is rendered on the page in two instances, one with values passed and one without. Since the presence of values is optional, I included a conditional operator in the default values of each input. In the case of the date input, it looks like this:

defaultValue={inputValues?.date ? inputValues.date : today}

In other cases, an empty string '' is used instead of today.

I expected that when the state changes, the component would re-render and insert the values into the default inputs. In practice, this only happens with inputs that are initially empty, while the date input always has the value today.

Through the console, I see that when the component is rendered, inputValue = undefined (useState is set with empty brackets, so it’s not a surprise), so initially I assumed that the values do not appear by the time of rendering. However, when the edit button is clicked, the correct values are displayed in the console. In my understanding, at this point, the component should re-render and insert the values according to the expression {inputValues?.date ? inputValues.date : today}. However, in fact, the value of the date picker is today, and the value of all other inputs is values. If you replace today with an '' in the expression, then when the edit function is called, the value of the date picker in the edit form is inputValues.date, but the default value in the creation form is now empty, because today is not set in this case.

This behavior is not exclusive to the date picker; any other input behaves in the same way if you replace '' with any value in the expression. I would be very glad if you could explain this behavior and how to fix it.

Here is a test example:”

function App() {
    const [values, setValues] = React.useState();
    const change = () => setValues({ name: 'name', date: '2023-11-28' });
    return (
        <Child values={values} change={change} />
    );
}

function Child({ values, change }) {
    console.log(values);
    return (
        <div className="container">
            <button type="button" onClick={change} >clickMe</button>
            <input type="text" defaultValue={values?.name ? values.name : ''} />
            <input type="date" defaultValue={values?.date ? values.date : '2023-11-20'} />
        </div>
    );
}

const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);

阅读 78

收藏
2023-11-30

共1个答案

小能豆

The behavior you’re experiencing is due to the fact that the defaultValue attribute is only evaluated once when the component mounts. Changing the values prop won’t re-evaluate the defaultValue attributes.

In your example, when the Child component mounts, the defaultValue attributes for the inputs are set based on the initial value of the values prop. Changing the values prop later won’t affect the already set defaultValue values.

To handle dynamic default values based on prop changes, you can use the value attribute instead of defaultValue and handle the input value with the useState hook.

Here’s an updated example:

function Child({ values, change }) {
  const [name, setName] = React.useState(values?.name || '');
  const [date, setDate] = React.useState(values?.date || '2023-11-20');

  React.useEffect(() => {
    setName(values?.name || '');
    setDate(values?.date || '2023-11-20');
  }, [values]);

  return (
    <div className="container">
      <button type="button" onClick={change}>
        clickMe
      </button>
      <input type="text" value={name} onChange={(e) => setName(e.target.value)} />
      <input type="date" value={date} onChange={(e) => setDate(e.target.value)} />
    </div>
  );
}

In this example, I’ve replaced defaultValue with value and added useState hooks to manage the input values. The useEffect hook is used to update the state when the values prop changes. Now, changing the values prop will correctly update the default values of the inputs.

2023-11-30