Загрузка изображений с помощью require в приложении react

#javascript #reactjs #create-react-app

#javascript #reactjs #create-react-app

Вопрос:

Я новичок в React и пытаюсь создать игру с картами, в которой websocket возвращает массив названий карт, а во внешнем интерфейсе я генерирую правильные изображения карт из локального каталога изображений. Имена карточек, возвращаемые из websocket, соответствуют имени файла изображения, например, «map» соответствует изображению «map.jpg «. Я пытаюсь отобразить массив и создать тег изображения для каждого имени карты в массиве. Я читал, что лучший способ — использовать require() , и поэтому я попытался сделать что-то вроде

 //inside component
let cardImgs;
...
socket.on(RECEIVED_STARTING_HAND, (hand) => {
     cardImgs = hand.map(cardName => <img src= {require(`../../card_images/${cardName}.jpg`)}/>
})
  

…Чтобы позже в моем компоненте я мог сделать что-то вроде этого:

 return (
 <div>
     <h1>My hand</h1>
        {cardImgs}
 </div>
  ...
)
  

Однако, cardImgs не выполняется рендеринг. В моей return инструкции моего компонента я протестировал рендеринг изображения напрямую, и это сработало, например

 const map = "map"
return (
 <div>
     <h1>My hand</h1>
        {cardImgs}
 </div>
  ...
//this one renders!!!
<img src={require(`../../card_images/${map}.jpg`)} /> 
)
  

Я создал свое приложение react с помощью Create-React-App и прочитал кое-что, в чем говорилось, что я должен перенастроить свой webpack.config.js файл, но затем я также прочитал кое-что, в чем говорилось, что я не должен трогать его без крайней необходимости. Я не уверен, почему require() это работает, когда я делаю это в return инструкции моего компонента, но это не работает, когда задан массив тегов изображений. Я что-то упускаю или у вас есть какие-либо предложения по улучшению способов динамической загрузки изображений в React? Спасибо!

Комментарии:

1. используйте import, который, несомненно, поможет.

2. У меня есть ~ 40 изображений, и я хочу динамически загружать изображения на основе предоставленных карточек. Наличие 40 инструкций импорта просто приводит к беспорядку. Я надеялся, что этому найдется альтернатива.

3. require не работает в react, единственный другой способ, который я могу придумать, — разместить изображение в облаке, таком как AWS или Azure, а затем вы сможете загружать его динамически.

4. Есть: разместите свои статические ресурсы как статические ресурсы вместо того, чтобы пытаться объединить их. Особенно, если есть данные, которые не будут меняться каждые полдня, такие как изображения, CSS сайта или webfonts. А затем загрузите их с помощью <img> компонента, потому что для этого и предназначен img элемент.

5. @Mike ‘Pomax’ Kamermans Не могли бы вы, пожалуйста, показать пример? Вы имеете в виду разместить их как статические ресурсы в облаке?

Ответ №1:

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

 {hand.map((cardName, index) => (
      <img key={cardName} src={`pathtoserver/card_images/${cardName}.jpg`}/>
     ))}
  

ДЕМОНСТРАЦИЯ

Комментарии:

1. Вы случайно не знаете, какой путь к серверу, если вы используете create-react-app? Я пытаюсь перемещаться, начиная с разных папок, но не могу найти правильный путь.

2. При создании приложения react у вас не будет доступа к серверу, поскольку это всего лишь упрощенная настройка сервера для разработки, если вы имеете в виду свой внутренний сервер, который зависит от вас.

3. у react нет доступа по умолчанию к данному серверу. статические ресурсы в create-react-app сохраняются в /public , если это вам поможет. это может помочь вам, если все ваши изображения карточек хранятся в приложении react, а не на сервере

4. @Mike’Pomax’Camermans хороший момент, не предполагающий ничего в приведенном выше примере, но обновит его

5. отлично, комментарий отозван. Люди думают, что они могут просто использовать позицию массива для key атрибута так часто , что это одна из основных причин, по которой приложения React работают плохо, когда они работают плохо.

Ответ №2:

если вы хотите отобразить изображение из локальной папки, вы можете импортировать нужные вам изображения с помощью синтаксиса import и после этого использовать его в своем теге img

 import card1 from '../you/path/to/image.png';
import card2 from '../you/path/to/image.png';
import card3 from '../you/path/to/image.png';

const cards = {
    nameToCard1: card1,
    nameToCard2: card2,
    nameToCard3: card3,
}
  

в вашем методе сокета:

 socket.on(RECEIVED_STARTING_HAND, (hand) => {
cardImgs = hand.map(cardName => cards[cardName] />
  

})

и в вашем методе рендеринга:

 return (
<div>
    <h1>My hand</h1>
    <ul>
        {cardImgs.map((img) => <li><img key={img} src={img} /></li>)}
    </ul>
</div>
  

)

надеюсь, это поможет вам, хорошего дня.

Комментарии:

1. не забудьте добавить key атрибуты при использовании map (и помните, что они должны быть реальными, уникальными значениями для компонента, а не «положением в массиве»)

2. О, вы правы. Я продолжу редактировать сообщение, чтобы получить правильный пример

3. И затем вы сделали именно то, что я напомнил вам не делать. Используйте уникальный идентификатор , то есть что-то, что всегда идентифицирует этот элемент : если у меня есть ['a','b'] и ['b','a'] , изменил ли я оба элемента или просто поменял их местами? Для этого key и используется. У вас уже есть идеальный уникальный идентификатор, он прямо здесь, вы уже назначаете его src , используйте его как ключ DOM diffing . Пожалуйста, прочитайте reactjs.org/docs/lists-and-keys.html#keys и поймите, почему вам нужно присвоить этому атрибуту правильное значение, потому что использовать позиции списка — значит подставлять себе ногу.

4. Спасибо за информацию, я приношу извинения и исправляю проблему, используя src изображения в качестве уникального идентификатора

5. Но почему key={`${img}`} ? Просто скажите key={img} ? И вы используете функцию со стрелкой, так что: <div><h1>..</h1><ul>{cardImgs.map(url => <li><img key={url} src={url} /></li>)}</ul></div> и готово?