0

我尝试使用从服务器获取的数据来渲染 visx wourdcloud。我用于显示网站的组件如下:

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { withRouter, RouteComponentProps, useParams } from 'react-router';

import WordCloud from '@/components/WordCloud';

import { getAggregations } from '@/selectors';

export interface WordData {
    text: string;
    value: number;
}

const AggregationShowComponent: React.FC<RouteComponentProps> = ({ history }) => {
    const dispatch = useDispatch();
    const { id }: { id: string } = useParams();
    const { loading, aggregations } = useSelector(getAggregations);

    const aggregation = aggregations.find(a => a._id == id);

    const words = [
        {
            text: 'a',
            value: 228
        },
        {
            text: 'b',
            value: 42
        },
    ];

    if (loading) {
        return (
            <div>Loading</div>
        )
    }

    return (
        <div>
            {aggregation._id}
            <WordCloud
                words={aggregation.data}
                // words={words}
                width={1024}
                height={600}
                spiral="archimedean"
                rotate="0"
            />
            <p>
                {aggregation.name}
            </p>
        </div>
    )
}

export const AggregationShow = withRouter(AggregationShowComponent);

负责渲染 wordcloud 的组件如下:

import React, { useState, useEffect } from 'react';
import { Text } from '@visx/text';
import { scaleLog } from '@visx/scale';
import { Wordcloud } from '@visx/wordcloud';

type SpiralType = 'archimedean' | 'rectangular';

export interface WordData {
  text: string;
  value: number;
}

interface WordCloudProps {
  width: number;
  height: number;
  words: WordData[],
  rotate: number,
  spiral: SpiralType,
  colors: String[],
}

const colors = ["#000000", "#aaaaaa", '#bbbbbb'];

const fixedValueGenerator = () => 0.5;

export default function WordCloud({ words, width, height, rotate = 0, spiral = 'archimedean' }: WordCloudProps) {

  const fontScale = scaleLog({
    domain: [Math.min(...words.map((w) => w.value)), Math.max(...words.map((w) => w.value))],
    range: [10, 100],
  });
  const fontSizeSetter = (datum: WordData) => fontScale(datum.value);

  return (
    <>
      <Wordcloud
        words={words}
        width={width}
        height={height}
        fontSize={fontSizeSetter}
        font={'Impact'}
        padding={2}
        spiral={spiral}
        rotate={rotate}
        random={fixedValueGenerator}
      >
        {(cloudWords) =>
          cloudWords.map((w, i) => (
            <Text
              key={w.text}
              fill={colors[i % colors.length]}
              textAnchor={'middle'}
              transform={`translate(${w.x}, ${w.y}) rotate(${w.rotate})`}
              fontSize={w.size}
              fontFamily={w.font}
            >
              {w.text}
            </Text>
          ))
        }
      </Wordcloud>
    </>
  );
}

如果我尝试使用请求中的数据(在aggregation.data 中找到),我会在d3.js 中收到以下错误: d3 只读错误

当我在第一个代码块的注释行中使用简单的静态数据时,它可以正常工作。仅当当前数据正常工作时,整个数据获取和显示也只有当我尝试使用 wordcloud 中的 http 请求中的数据时才会出现错误。

我还尝试克隆传递给 wordcloud 组件的数据,以确保某些 redux saga 对状态的影响不会导致错误,但错误保持不变。此外,我还尝试使用 useEffect 等重置数据,但仍然没有成功。

我错过了什么?react/d3 的某些部分是否会导致我不知道的这个问题?有没有办法绕过这个问题?

谢谢

4

1 回答 1

0

我找到了解决方案。d3-cloud 修改了 words 数组,这与 redux 存储数据的不变性发生了冲突。我只是创建了数组的深层副本:

.data.map(w = {...w})

不确定图书馆的任何其他部分是否应该阻止数据的编辑,但这对我有用!

于 2021-10-14T13:40:19.110 回答