Реагирует на функцию синтаксического анализа внутри компонента как элемент React. - PullRequest
0 голосов
/ 08 октября 2019

У меня есть компонент React, который пытается отобразить другой компонент, который имеет функцию внутри него, как дочерний элемент. Когда я пытаюсь отобразить этот компонент, он возвращает [Object] . Я пытаюсь найти другой способ визуализации этого дочернего компонента.

Прямо сейчас я пытался отрендерить его с помощью React.createElement () , но он также возвратил объект. Я использую библиотеку реагировать-красиво-dnd , чтобы использовать функцию перетаскивания. Эта библиотека имеет компонент Droppable, и она принимает внутри функцию, которая имеет два параметра: при условии , снимок .

Поскольку она принимает функцию, когда я пытаюсь отобразить Droppableкомпонента, он возвращает объект вместо элемента реагирования.

DroppableContent.js

const DroppableContent = ({ droppedBlank, label, id }) => (
  <Droppable droppableId={id || _.uniqueId('droppable_')}>
    {(provided, snapshot) => (
      <span ref={provided.innerRef} style={{ display: 'inline' }} {...provided.droppableProps}>
        {/* blank placeholder */}
        <span className={droppedBlank ? styles.dropped : styles.placeholder}
          style={{ backgroundColor: !droppedBlank && snapshot.isDraggingOver ? '#88d2ee' : '#fff' }}
        >
          {droppedBlank ? <BlankItem label={label} index={id} /> : null}
        </span>
      </span>
    )}
  </Droppable>
);

DragAndDrop.js , где я вызываю компонент QuestionPreview.

import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';

import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import _ from 'lodash';
import * as questionStyles from '../Questions.less';
import BlankList from './BlankList';
import BlankItem from './BlankItem';
import QuestionPreview from './QuestionPreview';

const DragAndDrop = ({
  question, onAnswer, answer, hideTitle, className, t, readOnly,
}) => {
  const handleDragEnd = (result) => {
    const { destination, source, draggableId } = result;
    if (!destination) {
      return;
    }

    if (destination.droppableId === source.droppableId && destination.index === source.index) {
      return;
    }

    const destinationId = destination.droppableId;
    const sourceId = draggableId;
    const blank = {
      textIndex: destinationId,
      id: sourceId,
      // answer: _.find(questionBlanks, b => b.id === sourceId).answer,
    };

    let updatedBlanks;
    if (destinationId === 'answerBlanks') {
      updatedBlanks = _.filter(answer.blanks, item => item.id !== blank.id);
    } else {
      updatedBlanks = _.filter(answer.blanks, item => item.textIndex !== blank.textIndex);
      updatedBlanks.push(blank);
    }

    onAnswer(question, { blanks: updatedBlanks });
  };

  const blankLabels = currentLabels => _.filter(currentLabels, l => !_.includes(_.map(answer.blanks, ab => ab.id), l.id)).map((label, index) => (
    <BlankItem key={label.id} label={label} index={index} />
  ));

  const blankItems = currentBlanks => _.map(currentBlanks, (currentBlank, index) => (
    <BlankItem key={currentBlank.id} label={currentBlank} index={index} readOnly />
  ));

  const { text } = question;
  const shuffledLabels = question.labels && _.shuffle(question.labels);
  // filtering answers from blank items so that whenever we drag an item to a blank,
  // answer will be removed.
  const filteredLabels = shuffledLabels && blankLabels(shuffledLabels);
  const filteredBlanks = blankItems(question.blanks);

  return (
    <DragDropContext onDragEnd={handleDragEnd}>
      <div>
        <p style={{ fontWeight: 600 }}>
          {t('defaultDndText', { numberOfBlanks: question.blanks.length })}
        </p>
        <Droppable droppableId="answerBlanks">
          {provided => (
            <div>
              <BlankList innerRef={provided.innerRef} {...provided.droppableProps}>
                {readOnly ? filteredBlanks : filteredLabels}
              </BlankList>
            </div>
          )}
        </Droppable>

        {!hideTitle && (
          <QuestionPreview blanks={_.filter(question.blanks, blank => blank.textIndex < 100)}
            labels={question.labels}
            selectedBlanks={answer.blanks}
            text={text}
            className={[questionStyles.title, className].join(' ')}
          />
        )}
      </div>
    </DragDropContext>
  );
};

DragAndDrop.propTypes = {
  question: PropTypes.shape({
    text: PropTypes.string,
  }).isRequired,
  answer: PropTypes.shape({
    blanks: PropTypes.arrayOf(PropTypes.shape({})),
  }),
  readOnly: PropTypes.bool,
  disabled: PropTypes.bool,
  hideTitle: PropTypes.bool,
  onAnswer: PropTypes.func,
  className: PropTypes.string,
};

DragAndDrop.defaultProps = {
  onAnswer: () => {},
  disabled: false,
  hideTitle: false,
  className: '',
  answer: { blanks: [] },
  readOnly: false,
};

export default withTranslation('question')(DragAndDrop);

QuestionPreview.js , где я пытаюсь отобразить компонент DroppableContent.

const QuestionPreview = ({
  text, labels, selectedBlanks, readOnly,
}) => {
  const readOnlyContent = (id) => {
    const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => blank.textIndex === id);
    const label = droppedBlank && _.find(labels, l => l.id === droppedBlank.id);
    return (
      <span className={droppedBlank ? styles.dropped : styles.placeholder}>
        {droppedBlank && <BlankItem label={label} readOnly />}
      </span>
    );
  };

  const splittedText = splitTextWithBlanks(text);
  const blankIndices = getBlankIndices(text);
  const getContentId = index => blankIndices[index];

  const tempArray = [];

  const html = () => {
    _.map(splittedText, (element, index) => {
      const contentId = getContentId(index);
      const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => blank.textIndex === contentId);
      const label = droppedBlank && _.find(labels, l => l.id === droppedBlank.id);
      const blankContent = readOnly ? readOnlyContent(contentId) : <DroppableContent id={contentId} droppedBlank={droppedBlank} label={label} />;
      const htmlContent = <span dangerouslySetInnerHTML={{ __html: toHTML(element) }} />;
      tempArray.push(htmlContent);
      if (index !== splittedText.length - 1) {
        tempArray[index] = tempArray[index] + blankContent;
      }
    });
    return tempArray;
  };

  const createdElement = React.createElement('div', null, html());
  return createdElement;
};

Это не возвращает никакой ошибки, но я хочу добиться того, чтобы объединение htmlContent переменная с blankContent . Когда я это делаю, он отрисовывает blankContent как объект. В конце я просто хочу найти способ разбора компонента Droppable.

1 Ответ

0 голосов
/ 08 октября 2019

У вас может быть ошибка в следующей строке

 const blankContent = readOnly ? readOnlyContent : <DroppableContent id={contentId} droppedBlank={droppedBlank} label={label} />;

Вы передаете ссылку readOnlyContent, возможно, вы хотите позвонить

readOnlyContent (contentId). Кстати, ваш код сложныйи трудно поддерживать / читать. попробуйте изменить его

Редактировать 1 Попробуйте это QuestionPreview.js

  const QuestionPreview = ({
    text, labels, selectedBlanks, readOnly,
        }) => {
    const readOnlyContent = (id) => {
    const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => 
                                       blank.textIndex === id);
    const label = droppedBlank && _.find(labels, l => l.id === 
                                       droppedBlank.id);
    return (
      <span className={droppedBlank ? styles.dropped : styles.placeholder}>
       {droppedBlank && <BlankItem label={label} readOnly />}
     </span>
    );
 };

  const splittedText = splitTextWithBlanks(text);
  const blankIndices = getBlankIndices(text);
  const getContentId = index => blankIndices[index];

  const tempArray = [];

  const html = () => {
   return _.map(splittedText, (element, index) => {
     const contentId = getContentId(index);
     const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => 
                                          blank.textIndex === contentId);
     const label = droppedBlank && _.find(labels, l => l.id === 
                                                        droppedBlank.id);
      const blankContent = readOnly ? readOnlyContent(contentId) : 
      <DroppableContent id={contentId} droppedBlank={droppedBlank} label= 
      {label} 
      />;
       let htmlContent = <span dangerouslySetInnerHTML={{ __html: 
                                                 toHTML(element) }} />;
    if (index !== splittedText.length - 1) {
        return (
         <Fragment>
           {htmlContent}
           {blankContent}
         </Fragment>
        ) 
     }

    return htmlContent
   });

  };

 return (
   {html()}
 )
};
...