Skip to content

Instantly share code, notes, and snippets.

@sergiy-rudenko
Forked from DavidP1983/CharList
Created January 12, 2022 02:01
Show Gist options
  • Select an option

  • Save sergiy-rudenko/4e25c0792ece74d172b70e709ae7d0b4 to your computer and use it in GitHub Desktop.

Select an option

Save sergiy-rudenko/4e25c0792ece74d172b70e709ae7d0b4 to your computer and use it in GitHub Desktop.

Revisions

  1. @DavidP1983 DavidP1983 created this gist Jan 12, 2022.
    179 changes: 179 additions & 0 deletions CharList
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,179 @@
    import { useState, useEffect, useRef } from 'react';
    // import { HideUntilLoaded } from 'react-animation';
    import PropTypes from 'prop-types';


    import Spinner from '../spinner/Spinner';
    import ErrorMessage from '../errorMessage/ErrorMessage';
    import MarvelServices from '../services/MarvelServices';

    import './charlist.scss';


    const CharList = (props) => {

    const [charList, setCharList] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);
    const [newItemLoading, setNewItemLoading] = useState(false);
    const [offset, setOffset] = useState(1548);
    const [charEnded, setCharEnded] = useState(true);


    console.log(offset);



    const marvelService = new MarvelServices();


    useEffect(() => {
    console.log('updateChar');
    updateChar();
    }, []);


    function handleScroll() {
    if (newItemLoading) return;

    if (charEnded) {

    if (window.pageYOffset + document.documentElement.clientHeight >= document.documentElement.scrollHeight) {
    onCharListLoading();
    updateChar(offset);

    }
    }
    }

    useEffect(() => {
    console.log('scroll');

    window.addEventListener('scroll', handleScroll);

    return () => {
    window.removeEventListener('scroll', handleScroll);
    console.log('unmount');

    }

    });



    const updateChar = (offset) => {

    onCharListLoading();

    marvelService.getAllCharacters(offset)
    .then(onCharListLoaded)
    .catch(onError)
    }

    //loading new items button disable
    const onCharListLoading = () => {
    setNewItemLoading(true);
    }

    const onCharListLoaded = (newCharList) => {
    let ended = true;
    if (newCharList.length < 9) {
    ended = false;
    }
    setCharList(charList => [...charList, ...newCharList]);
    setLoading(loading => false);
    setNewItemLoading(newItemLoading => false);
    setOffset(offset => offset + 9);
    setCharEnded(charEnded => ended);
    }


    const onError = () => {
    //We use without callback, because we don't mind wich state we have had before
    setError(true);
    setLoading(false);
    }

    const myRefs = useRef([]);


    // we use function declaration
    function renderItems(arr) {
    const items = arr.map((item, i) => {
    let imgStyle = { 'objectFit': 'cover' };
    if (item.thumbnail === 'http://i.annihil.us/u/prod/marvel/i/mg/b/40/image_not_available.jpg') {
    imgStyle = { 'objectFit': 'unset' };
    }

    return (
    // <HideUntilLoaded key={item.id} animationIn="bounceIn" durationOut={2000}>
    <li tabIndex={0}

    //instead of callback function setRef we will do all the stuff inside this map
    ref={elem => myRefs.current[i] = elem}

    className="char__item"
    key={item.id}
    onClick={() => props.onCharSelected(item.id, myRefs.current[i], myRefs.current)}
    onFocus={() => props.onCharSelected(item.id, myRefs.current[i], myRefs.current)}>
    <img src={item.thumbnail} alt={item.name} style={imgStyle} />
    <div className="char__name">{item.name}</div>
    </li>
    // </HideUntilLoaded>

    )
    });

    // А эта конструкция вынесена для центровки спиннера/ошибки
    return (

    <ul className="char__grid">
    {items}
    </ul>
    )
    }







    const items = renderItems(charList);

    const errorMessage = error ? <ErrorMessage /> : null;
    const spinner = loading ? <Spinner /> : null;
    const content = !(loading || error) ? items : null;

    // let name = charEnded ? 'There are no items to load' : 'load more';
    // const styleField = {
    // 'minWidth': '300px',
    // 'color': 'white',
    // 'filter': 'grayscale(.5)'
    // }

    return (
    <div className="char__list">
    {errorMessage}
    {spinner}
    {content}
    {/* <button className="button button__main button__long"
    disabled={newItemLoading}
    style={{'display': charEnded ? 'none' : 'block'}}
    // style={charEnded ? styleField : null}
    onClick={() => updateChar(offset)}>
    <div className="inner">{name}</div>
    </button> */}


    </div>
    )
    }



    CharList.propTypes = {
    onCharSelected: PropTypes.func.isRequired
    }

    export default CharList;