【问题标题】:React parsing function inside component as React Element组件内的 React 解析函数作为 React Element
【发布时间】:2019-10-08 20:56:40
【问题描述】:

我有一个 React 组件,它试图将另一个组件作为子组件呈现在其中。当我尝试渲染该组件时,它返回一个 [Object]。我正在尝试寻找另一种方式来呈现该子组件。

现在,我尝试使用 React.createElement() 渲染它,但它也返回了一个对象。我正在使用react-beautiful-dnd 库来使用拖放功能。这个库有 Droppable 组件,它有一个函数,里面有两个参数,providedsnapshot

由于它需要一个函数,当我尝试渲染 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 结合起来。当我这样做时,它会将空白内容呈现为对象。最后,我只是想找到一种方法来解析 Droppable 组件。

【问题讨论】:

  • 这里有语法错误{droppedBlank ? &lt;BlankItem label={label} index={id} /&gt; : &lt;span /&gt;} 放置null 而不是&lt;span/&gt;
  • 是的,它实际上曾经是 null。然后我尝试了一些东西并改变了它。不是语法错误,但通常 null 会更好。感谢您的信息:)
  • 你能分享你打电话给QuestionPreview的代码吗?我可能知道原因但想确认
  • 添加了DragAndDrop 组件,我称之为QuestionPreview

标签: reactjs parsing


【解决方案1】:

下面这行可能有错误

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

您正在传递readOnlyContent 的引用,可能是您想调用

readOnlyContent (contentId) .BTW 您的代码很复杂且难以维护/阅读。尝试重构它

编辑 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()}
 )
};

【讨论】:

  • 是的,我意识到它不容易阅读,因为我尝试了很多不同的东西 :) 再次是的,readOnlyContent 必须是 readOnlyContent(contentId) 但现在 readOnly 总是错误的。
  • 我只是想知道我是否能够解析 Droppable 组件。因为现在,react jsx 解析不起作用,因为它无法渲染组件内部的功能块。或者我用错了。
  • 感谢您的热情回复。经过少许修改,是的,上面的代码正在工作。但我想我无法解释自己。我的代码也在工作。但不是我想要的。我只需要找到一种方法来解析 html 内容中的Droppable 组件。问题是,当我尝试使用ReactDOMServer.renderToString() 方法时,它会渲染html,但不会渲染函数、道具等。因为Droppable 组件内部有一个函数。
猜你喜欢
  • 2021-03-09
  • 2019-06-13
  • 2020-06-12
  • 1970-01-01
  • 1970-01-01
  • 2017-11-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
相关资源
最近更新 更多