Home > Enterprise >  Render visx wordcloud after redux saga request is done and data is present leads to "read-only&
Render visx wordcloud after redux saga request is done and data is present leads to "read-only&

Time:10-18

I try to render a visx wourdcloud with the data that I get from my server. My component for showing the website is the following:

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);

The component responsible for rendering the wordcloud is the following:

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>
    </>
  );
}

If I try to use the data from the request (found in aggregation.data) I get the following error in d3.js: d3 read only error

When I use simple static data like in the commented out line in the first code block it works without any problems. The whole data fetching and displaying only when the data in present works also flawlessly only when i try to use the data from the http request in the wordcloud I get the error.

I also tried to clone the data that is passed into the wordcloud component to make sure that some of the redux saga effects on the state are not causing the error but the error remains the same. Additionally I also tried to reset the data with useEffect etc. but still no success.

What part am I missing? Is there some part of react/d3 that causes this issue that I'm not aware of? Is there a way to circumvent this problem?

Thanks

CodePudding user response:

I found the solution. The d3-cloud modifies the words array and that collides with the imutability of the redux store data. I simply created a deep copy of the array:

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

Not sure if any other parts of the libraries should prevent the editing of the data but this works for me!

  • Related