Не удается прочитать свойство 'appendChild' со значением NULL - Tiny Slider React - PullRequest
0 голосов
/ 16 января 2020

Реагируйте newb ie здесь, у меня проблемы с моим компонентом TinySlider. Каждый раз, когда я обновляю в пользовательском интерфейсе, сколько постов может появиться в карусели, я получаю эту ошибку при каждом другом обновлении, которое мне нужно исправить:

Uncaught (в обещании) TypeError: Невозможно прочитать свойство 'appendChild' из null

Если я удаляю <TinySlider settings={...settings}></Tinyslider>, я не получаю эту ошибку.

Я пробовал это: { renderProfilesCarousel ? renderProfilesCarousel : '' } внутри <tinySlider>, но это не работает.

Есть идеи, что я мог сделать здесь? Довольно застрял на этом сейчас.

// React
import * as React from 'react';
// Styling
import styles from './LinkedIn.module.scss';
// Importing the props
import { ILinkedInProps } from './ILinkedInProps';
// Importing the state
import { ILinkedInState } from './ILinkedInState';
// Removes special characters 
import { escape } from '@microsoft/sp-lodash-subset';
// Library for making http requests
import axios from 'axios';
// Library for creating unique ids
import shortid from 'shortid';
// Fabric UI elements
import {
  DocumentCard,
  DocumentCardPreview,
  DocumentCardType,
  DocumentCardDetails,
  DocumentCardTitle,
  IDocumentCardPreviewProps
} from 'office-ui-fabric-react/lib/DocumentCard';
import { ImageFit, Image } from 'office-ui-fabric-react/lib/Image';
// Sort array
import sortBy from 'sort-array';
import TinySlider from "tiny-slider-react";
import { SPComponentLoader } from '@microsoft/sp-loader';
import "./styles.scss";

// LinkedIn Component Class
export default class LinkedIn extends React.Component<ILinkedInProps, ILinkedInState> {

  // State needed for the component
  constructor(props) {
    super(props);
    this.state = {
        profiles: [],
        isLoading: true,
        errors: null
    };
    SPComponentLoader.loadCss('//cdnjs.cloudflare.com/ajax/libs/tiny-slider/2.9.2/tiny-slider.css');
  }

  // This function runs when component is first renderd
  public componentDidMount() {
    this.getProfiles();
  }

  // This function runs when props that have changed have been passed in
  public componentDidUpdate(prevProps) {
    if ( prevProps.listName !== this.props.listName || prevProps.postCount ! == this.props.postCount )
    {
      this.renderProfile();
    }
  }

  // Grabs LinkedIn profiles - This service runs once a day
  private getProfiles() {
    let companyNameCreate: string;
    let backUpImageCreate: string;
    axios
      .get(
        "https://cors-anywhere-spfx.herokuapp.com/" +
        "https://cache1.phantombooster.com/YRrbtT9qhg0/KJhwG7zo0zPE5zc9Eehn6Q/result.json"
      )
      .then(response => {
      this.setState({
        profiles: response.data.filter(d => d.postContent).map(post => {
          if (post.profileUrl == 'https://www.linkedin.com/company/')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQEbfV4VNvsJyg/company-logo_100_100/0?e=1587600000&v=beta&t=CX_s-ekYNn0TnXANeftQkLZ9jIvMW7PtDTLLcHcu9wY'
          }
          else if (post.profileUrl == 'https://www.linkedin.com/company/1')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQG_Pr1cDaGfdA/company-logo_200_200/0?e=1587600000&v=beta&t=C0fWkjbO2Elth8K4pG4i_kzwlu8dvQvN1Ws-yKGxxP4'
          }
          else if (post.profileUrl == 'https://www.linkedin.com/company/2')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQHdub-mnNwSNg/company-logo_100_100/0?e=1587600000&v=beta&t=druqo_O5gB5cExttREUlSdGnJhr4Wx2-PCjshJ0K0fI'
          }
          else if (post.profileUrl == 'https://www.linkedin.com/company/3')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQEUKGn5i1EnQA/company-logo_100_100/0?e=1587600000&v=beta&t=uwE3CUaodiqmW2K3a3Hm57QDIDlMvrmfmoHDvlGnzuY'
          }
          else if (post.profileUrl =='https://www.linkedin.com/company/4')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4D0BAQGYqqxF43Rfdg/company-logo_200_200/0?e=1587600000&v=beta&t=4hmLzdbkjk_hL3rwonWgTbUF1V-itkyBEfLBh85G7_k'
          }
          else if (post.profileUrl == 'https://www.linkedin.com/company/5')
          {
            companyNameCreate = 'company';
            backUpImageCreate = 'https://media-exp2.licdn.com/dms/image/C4E0BAQHsNKLawvW7zg/company-logo_100_100/0?e=1587600000&v=beta&t=26Otro4T3q90GznPxXX6n3oPTYYWIgzodOIask0enu4'
          }
          return {
            ...post,
            companyName: companyNameCreate,
            backUpImage:  backUpImageCreate
          }
        })
      });
    })
    // Error catching
    .catch(errors => this.setState({ errors, isLoading: false }));
  }

  // Creates the renderd layout of the LinkedIn profile
  private async renderProfile() {
    let filter: string = '';
    // Works out which profile to display
    switch (this.props.listName) {
      case "abfi":
        filter = 'https://www.linkedin.com/company/1';
        break;
      case 'abEnzymes':
        filter = 'https://www.linkedin.com/company/2';
        break;
      case 'abitec':
        filter = 'https://www.linkedin.com/company/3';
        break;
      case 'ohly':
        filter = 'https://www.linkedin.com/company/4';
        break; 
      case 'pgpi':
        filter = 'https://www.linkedin.com/company/5';
        break;
      case 'spiPharma':
        filter = 'https://www.linkedin.com/company/6';
        break;
      case 'all': 
        filter = 'Post';
        break;
      default:
        filter = 'https://www.linkedin.com/company/1';
        return filter;
    }

    // Grabs the array of objects
    let { profiles } = this.state;

    const slotOrder = [
      "", "1h","2h","3h","4h","5h","6h","7h","8h","9h","10h","11h","12h", "13h","14h","15h","16h","17h","18h","19h","20h","21h","22h", "23h", "2d", "3d", "4d", "5d", "6d", "1w", "2w", "3w", "1mo", "2mo", "3mo", "4mo", "5mo", "6mo", "7mo", "8mo", "9mo", "10mo", "11mo", "1yr", "2yr"
    ];

    // Select only the needed objects from the array
    let selectedProfile;

    // Display all posts 
    if (this.props.listName !== 'all') {
      selectedProfile = profiles.filter(profile => profile.profileUrl == filter);
    } else {
      selectedProfile = profiles.filter(profile => profile.action == filter);
    }

    selectedProfile = sortBy(selectedProfile, "postDate", { postDate: slotOrder })
    selectedProfile = selectedProfile.splice(0, this.props.postCount)

    // Renders the selected profile
    let renderProfilesCarousel = selectedProfile.map(profile => {

      // If LinkedIn post has no image, then add a fallback!
      if (profile.imgUrl == "" || profile.imgUrl == null ) {
        profile.imgUrl = profile.backUpImage;
      }

      // Removes hashtag line from posts
      profile.postContent = profile.postContent.replace(/hashtag/g, '');

      return(
        <div className={styles.linkedInContainerCarousel} style={{ position: "relative" }} key={shortid.generate()}>
          <a href={profile.postUrl} target="_blank" data-interception="off"> 
              <DocumentCard
                aria-label={profile.postContent}
                className={styles.linkedInDocCard}
              > 
                { profile.imgUrl && 
                  <Image
                    src={profile.imgUrl}
                    imageFit={ImageFit.cover}
                    height={168}
                  />
                }
                <DocumentCardTitle
                  title={profile.postContent}
                  shouldTruncate={true}
                />
                <p className={ styles.linkedInCompany}>{profile.companyName}</p>
                <p className={ styles.linkedInLikes}>{`Likes: ${profile.likeCount}`}</p>
              </DocumentCard>
          </a>
        </div>
      )
    });

    // Renders the selected profile
    let renderProfiles = selectedProfile.map(profile => {

      // If LinkedIn post has no image, then add a fallback!
      if (profile.imgUrl == "" || profile.imgUrl == null ) {
        profile.imgUrl = profile.backUpImage;
      }

      let previewProps: IDocumentCardPreviewProps = {
        previewImages: [
          {
            name: profile.postContent,
            previewImageSrc: profile.imgUrl,
            iconSrc: null,
            imageFit: ImageFit.cover,
            height: 110,
            width: 110
          }
        ]
      };

      return(
        <div className={styles.linkedInContainer} style={{ position: "relative" }} key={shortid.generate()}>
          <a href={profile.postUrl} target="_blank" data-interception="off"> 
              <DocumentCard
                aria-label={profile.postContent}
                className={styles.linkedInDocCard}
                type={DocumentCardType.compact}
              > 
                { profile.imgUrl && 
                  <DocumentCardPreview {...previewProps} />
                }
                <DocumentCardDetails>
                <DocumentCardTitle
                  title={profile.postContent}
                  shouldTruncate={true}
                />
                  <p className={ styles.linkedInCompany}>{profile.companyName}</p>
                  <p className={ styles.linkedInLikes}>{`Likes: ${profile.likeCount}`}</p>
                </DocumentCardDetails>
              </DocumentCard>
          </a>
        </div>
      )
    });

    let settings: any;

    if (this.props.toggleInfoHeaderValue == true )
    {
      settings = {
        lazyload: true,
        nav: false,
        mouseDrag: false,
        items: 1,
        swipeAngle: false,
        speed: 400,
        autoplay: false,
        axis: "horizontal",
        autoHeight: false,
        rewind: true,
        fixedWidth: false
      };
    }
    else
    {
      settings = {
        lazyload: true,
        nav: false,
        mouseDrag: false,
        items: 3,
        swipeAngle: false,
        speed: 400,
        autoplay: false,
        axis: "vertical",
        autoHeight: false,
        rewind: true,
        fixedWidth: false
      };
    };

    if (this.props.toggleInfoScrollValue) {
      settings.autoplay = true;
    } else {
      settings.autoplay = false;
    }

    if (this.props.toggleInfoHeaderValue == true ) {
      return(
        <div>
            <TinySlider settings={settings}>
               {renderProfilesCarousel}
            </TinySlider>
        </div>
      )
    } else {
      return (

        <div className={styles.upArrows}>
            <TinySlider settings={settings}>
               {renderProfiles}
            </TinySlider>
        </div>
      )
    }   

  } 

  // Renders to the browser
  public render(): React.ReactElement<ILinkedInProps> {

    return (
      <div className={ styles.linkedIn }>
        <div className={ styles.container }>
          <p className={ styles.title }>{escape(this.props.description)}</p>
          <div>
            { this.renderProfile() }
          </div>
        </div>
      </div>
    );
  }
} 

enter image description here

Полная ошибка: enter image description here

1 Ответ

1 голос
/ 17 января 2020

Советую попробовать вместо этого

{ renderProfilesCarousel ? renderProfilesCarousel : <span></span> }

Реагировать нравится, когда в нем есть элементов , и я не уверен, как бы он справился с ''

Изменить для редактирования:

Я думаю, вы захотите убрать фактический JSX.Element из метода renderProfile (). React не воспринимает это как дочерний элемент.

Итак, я добавил два новых элемента в состояние (я думаю, вы захотите три, один для renderProfilesCarousel):

settings?: any;
renderProfiles?: JSX.Element[];

Тогда Я сделал это в нижней части метода renderProfile ():


        /* if (this.props.toggleInfoHeaderValue == true) {
            return (
                <div>
                    <TinySlider settings={settings}>
                        {renderProfilesCarousel}
                    </TinySlider>
                </div>
            )
        } else {
            return (

                <div /* className={styles.upArrows} >
                    <TinySlider settings={settings}>
                        {renderProfiles}
                    </TinySlider>
                </div>
            )
        } */
        console.log(renderProfiles.length);
        this.setState({
            settings: settings,
            renderProfiles: renderProfiles,
            isLoading: false
        })

Затем, при возврате фактического рендера в браузер, я помещаю фактический JSX.Element:

    // Renders to the browser
    public render(): React.ReactElement<ILinkedInProfilesProps> {
        const {settings, renderProfiles} = this.state;
        const theRenderProfileJsxElement: JSX.Element = 
            <div /* className={styles.upArrows} */>
                <TinySlider settings={settings}>
                    {renderProfiles}
                </TinySlider>
            </div>;
        return (
            <div /* className={styles.linkedIn} */>
                <div /* className={styles.container} */>
                    <p /* className={styles.title} */>{escape(this.props.description)}</p>
                    <div>
                        {this.state.isLoading === false &&
                            theRenderProfileJsxElement
                        }
                    </div>
                </div>
            </div>
        );
    }

И я использовал ваше состояние isLoading, чтобы предотвратить загрузку карусели до завершения всех логов c и загрузки сверху.

Также! Если в вашем браузере нет React Dev Tools, он вам нужен!

enter image description here

Я вижу компонент Карусель, но я не выполнил команду if logi c ни для toggleInfoHeaderValue. Посмотрим, сработает ли это?

...