Функция onClick компонента React.JS, как быть более конкретным с его результатом - PullRequest
0 голосов
/ 07 мая 2018

В настоящее время у меня есть компонент React, который берет данные о музыкальных исполнителях из API и создает список объектов мультимедиа, показывающих детали этого. Мультимедийные объекты имеют функцию onClick, поэтому при щелчке по блоку отображается дочерний компонент с более конкретными сведениями, что все работает,

ОДНАКО при нажатии на один объект в списке они ВСЕ отображают дочерние компоненты под ними. Как мне сузить это, чтобы каждый объект в списке можно было нажимать по отдельности, не затрагивая другие?

Вот мой код:

import React, { Component } from 'react';
import axios from 'axios';
import ArtistChild from './track-child';

class ArtistListEntry extends Component {
  constructor(props) {
   super(props);

   this.state = {
     error: null,
     isHidden: true,
     artist: []
   };
 }

 toggleHidden () {
    this.setState({
      isHidden: !this.state.isHidden
    })
  }

 componentDidMount() {
   this.ArtistListEntry();
 }

 ArtistListEntry() {
   axios.get('https://api-v2.hearthis.at/feed/?type=popular&page=1&count=20')
     .then(
       ({ data }) => {
         this.setState({
           artist: data
         })
       })
       .catch((error) => {
        if (error.response) {
            console.log(error.response.status);
            console.log(error.response.headers);
        } else if (error.request) {
            console.log(error.request);
        } else {
            console.log('Error', error.message);
        }
        console.log(error.config);
    });
 }

 render() {
   let artists = this.state.artist.map((item) => (
     <div>
       <div className='media media-top' key={ item.user.id } onClick={this.toggleHidden.bind(this)}>
        <div className='media-left media-middle'>
          <img src={ item.user.avatar_url } className='media-object artist-image' />
        </div>
        <div className='media-body'>
          <ul className='artist-info-list'>
            <li className='media-heading'>{ item.user.username }</li>
            <li className='media-genre'>{ item.genre }</li>
            <a className='media-release' href={ item.permalink_url }>Visit Artist Page</a>
          </ul>
        </div>
      </div>
      {!this.state.isHidden && <ArtistChild />}
    </div>
  ));

   return (
     <div id="layout-content" className="layout-content-wrapper">
       <div className="panel-list">
         { artists }
       </div>
     </div>
   );
 }
}

export default ArtistListEntry;

Заранее спасибо!

Ответы [ 4 ]

0 голосов
/ 07 мая 2018

Ваш код будет выглядеть как

toggleHidden (item) {
    item.isHidden  = (!item.isHidden) || true;
    this.forceUpdate();
  }

код рендеринга

let artists = this.state.artist.map((item) => (
     <div>
       <div className='media media-top' key={ item.user.id } onClick={this.toggleHidden.bind(this, item)}>
        <div className='media-left media-middle'>
          <img src={ item.user.avatar_url } className='media-object artist-image' />
        </div>
        <div className='media-body'>
          <ul className='artist-info-list'>
            <li className='media-heading'>{ item.user.username }</li>
            <li className='media-genre'>{ item.genre }</li>
            <a className='media-release' href={ item.permalink_url }>Visit Artist Page</a>
          </ul>
        </div>
      </div>
      {item.isHidden && <ArtistChild />}
    </div>
  ));


//  you need to check {item.isHidden && <ArtistChild />}
0 голосов
/ 07 мая 2018

Вы поддерживаете одно состояние, чтобы переключать представление, которое является одинаковым для всех элементов списка, поэтому либо вам нужно поддерживать список для скрытых элементов, либо лучший способ сохранить, какой элемент должен отображаться (если только один должен отображаться сразу)

import React, { Component } from 'react';
import axios from 'axios';
import ArtistChild from './track-child';

class ArtistListEntry extends Component {
  constructor(props) {
   super(props);

   this.state = {
     error: null,
     isVisible: '',
     artist: []
   };
 }

 toggleHidden (id) {
    this.setState({
      isVisible: id
    })
  }

 componentDidMount() {
   this.ArtistListEntry();
 }

 ArtistListEntry() {
   axios.get('https://api-v2.hearthis.at/feed/?type=popular&page=1&count=20')
     .then(
       ({ data }) => {
         this.setState({
           artist: data
         })
       })
       .catch((error) => {
        if (error.response) {
            console.log(error.response.status);
            console.log(error.response.headers);
        } else if (error.request) {
            console.log(error.request);
        } else {
            console.log('Error', error.message);
        }
        console.log(error.config);
    });
 }

 render() {
   let artists = this.state.artist.map((item) => (
     <div>
       <div className='media media-top' key={ item.user.id } onClick={this.toggleHidden.bind(this, item.id)}>
        <div className='media-left media-middle'>
          <img src={ item.user.avatar_url } className='media-object artist-image' />
        </div>
        <div className='media-body'>
          <ul className='artist-info-list'>
            <li className='media-heading'>{ item.user.username }</li>
            <li className='media-genre'>{ item.genre }</li>
            <a className='media-release' href={ item.permalink_url }>Visit Artist Page</a>
          </ul>
        </div>
      </div>
      {this.state.isVisible === item.id  && <ArtistChild />}
    </div>
  ));

   return (
     <div id="layout-content" className="layout-content-wrapper">
       <div className="panel-list">
         { artists }
       </div>
     </div>
   );
 }
}

export default ArtistListEntry; 

В случае необходимости переключения нескольких элементов необходимо поддерживать открытое состояние для всех элементов

import React, { Component } from 'react';
import axios from 'axios';
import ArtistChild from './track-child';

class ArtistListEntry extends Component {
  constructor(props) {
   super(props);

   this.state = {
     error: null,
     isHidden: {},
     artist: []
   };
 }

 toggleHidden (itemId) {
    this.setState(prevState => ({
      isHidden: {[itemId]: prevState.isHidden[itemId] ? !prevState.isHidden[itemId] : false
    }))
  }

 componentDidMount() {
   this.ArtistListEntry();
 }

 ArtistListEntry() {
   axios.get('https://api-v2.hearthis.at/feed/?type=popular&page=1&count=20')
     .then(
       ({ data }) => {
         this.setState({
           artist: data
         })
       })
       .catch((error) => {
        if (error.response) {
            console.log(error.response.status);
            console.log(error.response.headers);
        } else if (error.request) {
            console.log(error.request);
        } else {
            console.log('Error', error.message);
        }
        console.log(error.config);
    });
 }

 render() {
   let artists = this.state.artist.map((item) => (
     <div>
       <div className='media media-top' key={ item.user.id } onClick={this.toggleHidden.bind(this)}>
        <div className='media-left media-middle'>
          <img src={ item.user.avatar_url } className='media-object artist-image' />
        </div>
        <div className='media-body'>
          <ul className='artist-info-list'>
            <li className='media-heading'>{ item.user.username }</li>
            <li className='media-genre'>{ item.genre }</li>
            <a className='media-release' href={ item.permalink_url }>Visit Artist Page</a>
          </ul>
        </div>
      </div>
      {!this.state.isHidden[item.id]  && <ArtistChild />}
    </div>
  ));

   return (
     <div id="layout-content" className="layout-content-wrapper">
       <div className="panel-list">
         { artists }
       </div>
     </div>
   );
 }
}

export default ArtistListEntry;
0 голосов
/ 07 мая 2018

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

Должно выглядеть примерно так:

// ...

class ArtistListEntry extends Component {
  constructor(props) {
   super(props);

   this.state = {
     error: null,
     activeArtistId: null,
     artist: []
   };
 }

 toggleHidden (artistId) {
    this.setState({
      activeArtistId: artistId
    })
  }

 // ...

 ArtistListEntry() {
   axios.get('...')
     .then(
       ({ data }) => {
         this.setState({
           artist: data,
           activeArtistId: null
         })
       })

       // ...
 }

 render() {
   let artists = this.state.artist.map((item) => (
     <div>
       <div className='media media-top' key={ item.user.id } onClick={this.toggleHidden.bind(this, item.user.id)}>
        {/*...*/}
      </div>
      {this.state.activeArtistId === item.user.id && 
       <ArtistChild artistId={item.user.id} />}
    </div>
  ));

   // ...
 }
}
0 голосов
/ 07 мая 2018

Обновите свой onClick, чтобы получить идентификатор скрытого объекта, и ваше состояние будет делать то же самое:

this.state = {
     error: null,
     hidden: {},
     artist: []
};

Тогда ваш onClick будет таким:

onClick={() => {
  this.setState(prevState => {
    return { hidden: { ...prevState, [item.user.id]: !prevState.hidden[item.user.id] } };
  });
}}

Затем вы проверите, имеет ли значение state.hidden [item.user.id]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...