Условный оператор не учитывает изменения условия

У меня есть React компонент, представляющий форму с инпутами (Текст, Числа, Дата). В инпуте даты есть значение по умолчанию - сегодня(today). Я использую один этот компонент для двух функций: создания объекта и для редактирования объекта. В первом случае все инпуты по умолчанию пустые, кроме инпута даты, в него предаётся значения today. Во втором случае, инпуты получают значение по умолчанию из опциональных пропсов(values), которые поступают в компонент из стейта родительского компонента. Компонент рендериться на странице в двух экземплярах, в один values передаются, в другой нет. Поскольку наличие values опционально, я включил в дефолтные значения каждого импута условный оператор. В случае с импутом даты он выглядит так:

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

В остальных случаях, вместо today ставится пустая строка ''.

Я ожидал, что при изменении стейта, компонент будет ререндериться и вставлять в дефолт инпута, значения values. На практике же, так происходит только с теми инпутами, которые по умолчанию пустые, а инпут с датой, всегда имеет значение today.

Через консоль я вижу, что при рендере компонента inputValue имеет значение undefiend (useState стоит с пустыми скобками), поэтому я по началу предположил, что values не успевают появится к моменту рендера. Однако при нажатии на кнопку редактирования, корректные values высвечиваются в консоли. В моём понимании в этот момент, компонент должен ререндериться и подставить значение values, в соответствии с выражением {inputValues?.date ? inputValues.date : today} Однако по факту, значение календарая = today, а значение всех остальных импутов = values. Если же в выражении заменить today на пустую строку, то при вызове функции редактирования, значение календаря в форме редактирования = inputValues.date, однако дефолтное значение в форме создания теперь пустое, т.к. today в этом случае не задан.

Такое поведение не исключительно для календаря, любой другой инпут ведёт себя таким же образом, если в выражении, заменить пустую строку на любое значение. Буду очень рад, если объясните такое поведение и как его исправить.

Тестовый пример


    import React, { useState } from 'react';
    
    export default function Parent() {
      const [values, setValues] = 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>
      );
    }


Ответы (1 шт):

Автор решения: ksa

Действительно - defaultValue ведет себя довольно странно.

Я пошарился по интернету - с такой проблемой столкнулся не только ты. В итоге предлагают вот такое "решение" проблемы. Нужно "проблемному" инпуту дать атрибут key, да такой, чтобы он менялся каждый раз при рендере. Т.о. элемент начинает реагировать на изменение стейта в его defaultValue.

//    
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);
  const v1 = values.name ? values.name : ''
  const v2 = values.date ? values.date : '2023-11-20'
  const k = v2 ? v2 : (new Date()).toString()
  return (
    <div className="container">
      <button type="button" onClick={change} >clickMe</button>
      <input type="text" defaultValue={v1} />
      <input key={k} type="date" defaultValue={v2} />
    </div>
  );
}

const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<div id="like_button_container"></div>

→ Ссылка