Текст ввода - defaultValue не загружает значение состояния, а значение не обновляется при изменении - PullRequest
0 голосов
/ 09 мая 2020

У меня есть следующий вводимый текст ( MovieInput.tsx ):

<input 
    id="inputMovieTitle" 
    type="text"
    onChange={ e => titleHandleChange(e) }
    value={ getTitle() }>
</input>

titleHandleChange:

const [title, setTitle] = useState('');

const titleHandleChange = (e: ChangeEvent<HTMLInputElement>) => {        
    setTitle(e.target.value);
}

getTitle:

const moviesInState = useSelector((state: any) => state.movies);

const getTitle = () => {      
    console.log(moviesInState.item.title); // It displays correct movie title from the store corresponding to the selected row
    return moviesInState.item.title;
}

У меня есть таблица (Grid.tsx), в которой перечислены все фильмы из штата (state.movies.items []). Когда я нажимаю любую строку mov ie в этой таблице, выбранный mov ie будет обновлен в магазине, то есть state.movies.item.

Grid.tsx:

const dispatch = useDispatch();

const selectMovie = (movie: Movie) => {
    const movieSelected: Movie = {
        _id: movie._id,
        __v: movie.__v,
        title: movie.title,
        rating: movie.rating,
        year: movie.year
    }
    dispatch(getMovie(movieSelected));
}
...
<tbody>
    {
        props.allMovies.map((movie: Movie) => 
            <tr onClick={() => selectMovie(movie)}>
                <td>{movie.title}</td>
                <td>{(+movie.rating).toFixed(1)}</td>
                <td>{movie.year}</td>
            </tr>
        )
    }
</tbody>

Теперь, когда я щелкаю любую строку в таблице (Grid.tsx), она обновляет store.movies.item в магазине, а ввод текста (в MovieInput.tsx) показывает заголовок mov ie выбрано. Когда я изменяю выбранную строку, значение текстового ввода также обновляется.

Почему я загружаю выбранный текст заголовка mov ie в текстовый ввод?

Потому что я должен иметь возможность редактировать значение заголовка и обновлять запись в БД. Я выбираю любую строку, меняю ее заголовок, затем нажимаю кнопку «Обновить» и сохраняю. Однако, хотя текст успешно заполнен в поле ввода текста и правильно изменяется, пока мы изменяем выбранную строку, ввод текста остается «нередактируемым». Это происходит из-за следующего кода:

value={ getTitle() }>

Когда я меняю 'value' на 'defaultValue' следующим образом, я могу редактировать ввод текста, но на этот раз текстовое значение не меняется, когда Я выбираю другую строку.

defaultValue={ getTitle() }>

Он просто отлично работает и показывает обновленные значения (когда я меняю выбранные строки), пока я не отредактирую ввод. Когда он редактируется в первый раз, он не меняет свое значение при следующем щелчке строки. Остается только отредактированный текст, но я ожидаю, что значение изменится, когда я выберу другую строку. Однако в журнале консоли внутри функции getTitle () отображается правильный заголовок из магазина (store.movies.item), соответствующий выбранной строке.

Не могли бы вы сообщить мне, как сделать следующее?

  • сделать текстовый ввод редактируемым
  • заставить текстовый ввод изменить свое значение после изменения выбранной строки (даже если ввод был отредактирован до того, как он должен потерять редактирование и перейти на новое значение)

1 Ответ

1 голос
/ 09 мая 2020

Причина, по которой input не отображает обновленное значение после изменения, заключается в том, что он привязан к значению из вашего хранилища redux через moviesInState.

Из того, что я вижу, вам нужно исходное значение входных данных, которые должны поступать из getTitle(), тогда как обновленные значения входных данных должны поступать из того, что пользователь ввел.

Следовательно, первое, что вы должны изменить, это установить начальное значение title состояние со значением из хранилища.

const moviesInState = useSelector((state: any) => state.movies);
const getTitle = () => {      
    console.log(moviesInState.item.title); // It displays correct movie title from the store corresponding to the selected row
    return moviesInState.item.title;
}
const [title, setTitle] = useState(getTitle());

И, учитывая, что входные данные должны обновляться по мере обновления хранилища, для распространения обновления в состоянии требуется ловушка useEffect.

useEffect(() => {
  if (moviesInState.item.title !== title) {
    setTitle(moviesInState.item.title);
  }
}, [moviesInState]);

Затем привяжите состояние title к value реквизитам input. С методом titleHandleChange проблем нет, поэтому мы можем оставить все как есть. Кроме того, нет необходимости полагаться на defaultValue, поэтому мы можем отказаться от его использования.

<input 
  id="inputMovieTitle" 
  type="text"
  onChange={titleHandleChange}
  value={title}>
</input>

С другой стороны, вы не должны использовать any, так как это лишит преимущества возможностей проверки типов TypeScript. Вместо этого вы должны определить параметр state как тип состояния root, который вы определили для своего хранилища redux. Например,

const moviesInState = useSelector((state: RootState) => state.movies);
...