Компоненты React Duplicate обновляют неправильное состояние: хуки

Я новичок, чтобы реагировать, использую его всего несколько дней, так что простите меня, если это глупый вопрос.

У меня есть компонент ввода файла и компонент миниатюры изображения, я использую два дублирующих компонента ввода файла для обновления двух разных состояний, а затем отображаю изображение из разных состояний в двух разных компонентах миниатюры. У меня установлены уникальные ключи для всех компонентов, но обновляется только состояние первого компонента в Доме. Когда я добавляю изображение, используя второй ввод файла, он обновляет состояние, принадлежащее первому вводу файла.

Я пытался искать решения, и все они заявляют об использовании уникальных ключей, что, я думаю, я сделал правильно.

let [certification, setCertification] = useState(null)
let [photoId, setPhotoId] = useState(null)

let handleUpdateCertificate = (e) =>{
    let file = e.target.files[0]
    console.log(file)
    let path = URL.createObjectURL(file)

    let newCertificate = {
        'file': file,
        'path' : path
    }

    setCertification(newCertificate)
}

let handleUpdatePhotoId = (e) => {
    let file = e.target.photoidinput.files[0]
    let path = URL.createObjectURL(file)

    let newPhotoID = {
        'file': file,
        'path' : path
    }

    setPhotoId(newPhotoID)

}

Мой возвращаемый html:

     <div className='justify-content-center margin-20' key='certificate-wrapper'>
        <ImgThumbnail key={'certificate'} name={'certificate'} image= 
             {certification?.path} wrapperClass={'justify-content-center margin-20'}/>
      </div>
      <div className='justify-content-center margin-20'>
         <FileInput key={'certificateinput'} name={'certificateinput'} labelText={<p 
                    className='text-paragraph edit-btn-text'>Add Certificate</p>} 
                     onChange={handleUpdateCertificate}
                     classWrapper={'edit-profile-responsive-btn-wrapper'}/>
      </div>
  <div className='justify-content-center margin-20 ' key='photo-Id'>
       <ImgThumbnail key={'photoid'} name={'photoId'} image={photoId?.path} 
                  wrapperClass={'justify-content-center margin-20'}/>
  </div>
                            
  <div className='justify-content-center margin-20' key='photo-id-input-wrapper'>
      <FileInput key={'photoidinput'} name={'photoidinput'} labelText={<p 
                  className='text-paragraph edit-btn-text'>Add Photo ID</p>} 
                  onChange={handleUpdatePhotoId}
                  classWrapper={'edit-profile-responsive-btn-wrapper'}/>
   </div>
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
Приложение для отслеживания бюджета на React js для начинающих
Приложение для отслеживания бюджета на React js для начинающих
Обучение на практике - это проверенная тема для достижения успеха в любой области. Если вы знаете контекст фразы "Практика делает человека...
Стоит ли использовать React в 2022 году?
Стоит ли использовать React в 2022 году?
В 2022 году мы все слышим о трендах фронтенда (React, Vue), но мы не знаем, почему мы должны использовать эти фреймворки, когда их использовать, а...
Как передать состояние или данные в react-router v6
Как передать состояние или данные в react-router v6
react-router - это лучшая библиотека для работы с маршрутизацией в reactjs. С помощью react-router вы передаете состояние или данные от одного...
0
0
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хорошо, я дам вам несколько советов, а затем приведу рабочий пример:

  • Вам не нужно устанавливать атрибут ключ, если вы пишете такие элементы JSX, вам это нужно, только если вы визуализируете список элементов из массива, чтобы предотвратить бесполезный повторный рендеринг при обновлении массива.

  • используйте константа вместо let, когда переменная статическая, об этом есть правило lint!

  • Попробуйте использовать DRY, ваши обработчики обновлений разделяют много логики, если вы собираетесь добавить больше входных данных, которые будут повторять весь код.

Теперь код:

import React, { useState } from 'react';
import './style.css';

export default function App() {
  const [certification, setCertification] = useState(null);
  const [photoId, setPhotoId] = useState(null);

  const updateData = (file, cb) => {
    const path = URL.createObjectURL(file);
    const data = {
      file: file,
      path: path,
    };
    cb(data);
  };

  const handleUpdateCertificate = (e) => {
    updateData(e.target.files[0], setCertification);
  };

  const handleUpdatePhotoId = (e) => {
    updateData(e.target.files[0], setPhotoId);
  };

  return (
    <div>
      {certification && (
        <div className="justify-content-center margin-20">
          <ImgThumbnail
            name={'certificate'}
            image={certification?.path}
            wrapperClass={'justify-content-center margin-20'}
          />
        </div>
      )}
      <div className="justify-content-center margin-20">
        <FileInput
          id="certificate"
          name={'certificateinput'}
          labelText={
            <p className="text-paragraph edit-btn-text">Add Certificate</p>
          }
          onChange={handleUpdateCertificate}
          classWrapper={'edit-profile-responsive-btn-wrapper'}
        />
      </div>
      {photoId && (
        <div className="justify-content-center margin-20 " key="photo-Id">
          <ImgThumbnail
            name={'photoId'}
            image={photoId?.path}
            wrapperClass={'justify-content-center margin-20'}
          />
        </div>
      )}

      <div
        className="justify-content-center margin-20"
        key="photo-id-input-wrapper"
      >
        <FileInput
          id="photo"
          name={'photoidinput'}
          labelText={
            <p className="text-paragraph edit-btn-text">Add Photo ID</p>
          }
          onChange={handleUpdatePhotoId}
          classWrapper={'edit-profile-responsive-btn-wrapper'}
        />
      </div>
    </div>
  );
}

const FileInput = ({ id, labelText, ...props }) => (
  <label htmlFor={id}>
    {labelText}
    <input id={id} style={{ display: 'none' }} type="file" {...props} />
  </label>
);

const ImgThumbnail = ({ name, image }) => (
  <div>
    <img style={{ width: '100px', height: '100px' }} src={image} alt={name} />
  </div>
);

Этот пример работает правильно, вы, вероятно, делали что-то не так внутри компонента ФайлВвод, помните, что метка должна иметь атрибут htmlДля с я бы элемента вход, который вы хотите активировать.

Теперь этот код можно оптимизировать и сделать в стиле Реагировать, поскольку в будущем у вас может быть больше входных файлов, давайте посмотрим, как его можно оптимизировать, создав повторно используемые компоненты и правильно их скомпоновав:

import React, { useState } from 'react';
import './style.css';

/* INPUTS IMAGE TYPES */

const inputs = [
  { type: 'photo', name: 'photo', label: 'Photo' },
  { type: 'certificate', name: 'certificate', label: 'Certificate' },
  { type: 'anotherType', name: 'anotherName', label: 'Another Input' },
];

export default function App() {
  return (
    <div>
      {inputs.map((data) => (
        <ImagePreviewer key={data.type} data={data} />
      ))}
    </div>
  );
}

const FileInput = ({ id, labelText, ...props }) => (
  <label htmlFor={id}>
    {labelText}
    <input id={id} style={{ display: 'none' }} type="file" {...props} />
  </label>
);

const ImgThumbnail = ({ name, image }) => (
  <div>
    <img src={image} alt={name} />
  </div>
);

const ImagePreviewer = ({ data: { type, name, label } }) => {
  const [image, setImage] = useState(null);

  const updateData = (file, cb) => {
    const path = URL.createObjectURL(file);
    const data = {
      file: file,
      path: path,
    };
    cb(data);
  };

  const handleUpdate = (e) => {
    updateData(e.target.files[0], setImage);
  };

  return (
    <div>
      {image && (
        <div>
          <ImgThumbnail name={'name'} image={image?.path} />
        </div>
      )}
      <div>
        <FileInput
          id={name}
          name={name}
          labelText={<p>Add {label}</p>}
          onChange={handleUpdate}
        />
      </div>
    </div>
  );
};

Рабочая демонстрация ЗДЕСЬ.

Это БЫЛО что-то глупое. Но я рад, что задал вопрос. Я не знал, что для const существует правило lint, все видео, которые я смотрел, использовали let. Спасибо, что нашли время написать второй блок кода! Мне нравится, как это сделано! Я учу себя реагировать, так что это огромная помощь!

scarlettiron 08.04.2022 15:35

Другие вопросы по теме