skip to Main Content

I am following Colt Steele’s React course. Sadly, the course is outdated so I chose to use function components instead of class based ones.
Currently I am stuck on a problem that I don’t understand. I’ll show my code and the error message.

colorHelpers.js:7  Uncaught TypeError: Cannot read properties of undefined (reading 'paletteName')
    at generatePalette (colorHelpers.js:7:1)
    at PaletteWrapper (App.js:17:1)
    at renderWithHooks (react-dom.development.js:16305:1)
    at mountIndeterminateComponent (react-dom.development.js:20074:1)
    at beginWork (react-dom.development.js:21587:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
    at invokeGuardedCallback (react-dom.development.js:4277:1)
    at beginWork$1 (react-dom.development.js:27451:1)
    at performUnitOfWork (react-dom.development.js:26557:1)

App.js

import { Routes, Route, useParams } from "react-router-dom";

import { generatePalette } from "./colorHelpers";
import Palette from "./Palette";
import seedColors from "./seedColors";

function App() {
  const findPalette = (id) => {
    const palette = seedColors.find((palette) => palette.id === id);
    console.log(palette);
    return palette;
  };

  const PaletteWrapper = () => {
    const { id } = useParams();

    const palette = generatePalette(findPalette(id));

    return <Palette palette={palette} />;
  };

  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<h1>Welcome Home</h1>} />
        <Route path="/palette/:id" element={<PaletteWrapper />} />
      </Routes>

      {/* <Palette palette={generatePalette(seedColors[3])} /> */}
    </div>
  );
}

export default App;

Palette.js

import { useState } from "react";
import ColorBox from "./ColorBox";
import { Navbar } from "./Navbar";
import "./Palette.css";

const Palette = (props) => {
  const [level, setLevel] = useState(500);
  const [format, setFormat] = useState("hex");

  const changeFormat = (format) => {
    setFormat(format);
  };

  const changeLevel = (newLevel) => {
    setLevel(newLevel);
  };

  const { colors, paletteName, emoji } = props.palette;

  const colorBoxes = colors[level].map((color) => (
    <ColorBox key={color.name} background={color[format]} name={color.name} />
  ));

  return (
    <div className="Palette">
      <Navbar
        level={level}
        changeLevel={changeLevel}
        changeFormat={changeFormat}
        format={format}
      />
      <div className="Palette-colors">{colorBoxes}</div>
      <div className="Palette-footer">
        {paletteName}
        <span className="emoji">{emoji}</span>
      </div>
    </div>
  );
};

export default Palette;

colorHelpers.js

import chroma from "chroma-js";

const levels = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];

export function generatePalette(starterPalette) {
  let newPalette = {
    paletteName: starterPalette.paletteName,
    id: starterPalette.id,
    emoji: starterPalette.emoji,
    colors: {},
  };

  for (let level of levels) {
    newPalette.colors[level] = [];
  }

  for (let color of starterPalette.colors) {
    let scale = getScale(color.color, 10).reverse();
    for (let i in scale) {
      newPalette.colors[levels[i]].push({
        name: `${color.name} ${levels[i]}`,
        id: color.name.toLowerCase().replace(/ /g, "-"),
        hex: scale[i],
        rgb: chroma(scale[i]).css(),
        rgba: chroma(scale[i])
          .css()
          .replace("rgb", "rgba")
          .replace(")", ",1.0)"),
      });
    }
  }
  return newPalette;
}

function getRange(hexColor) {
  const end = "#fff";
  return [chroma(hexColor).darken(1.4).hex(), hexColor, end];
}

function getScale(hexColor, numOfColors) {
  return chroma.scale(getRange(hexColor)).mode("lab").colors(numOfColors);
}

seedColors.js

export default [
  {
    paletteName: "Material UI Colors",
    id: "material-ui-colors",
    emoji: "🎨",
    colors: [
      { name: "red", color: "#F44336" },
      { name: "pink", color: "#E91E63" },
      { name: "purple", color: "#9C27B0" },
      { name: "deeppurple", color: "#673AB7" },
      { name: "indigo", color: "#3F51B5" },
      { name: "blue", color: "#2196F3" },
      { name: "lightblue", color: "#03A9F4" },
      { name: "cyan", color: "#00BCD4" },
      { name: "teal", color: "#009688" },
      { name: "green", color: "#4CAF50" },
      { name: "lightgreen", color: "#8BC34A" },
      { name: "lime", color: "#CDDC39" },
      { name: "yellow", color: "#FFEB3B" },
      { name: "amber", color: "#FFC107" },
      { name: "orange", color: "#FF9800" },
      { name: "deeporange", color: "#FF5722" },
      { name: "brown", color: "#795548" },
      { name: "grey", color: "#9E9E9E" },
      { name: "bluegrey", color: "#607D8B" },
    ],
  },
  ...

enter image description here

I’ve tried looking at the findPalette and generatePalette functions, at the palette component but I haven’t resulted in anything but this error.

2

Answers


  1. Your issue is with PaletteWrapper

    const PaletteWrapper = () => {
      const { id } = useParams();
    
      const foundPalette = findPalette(id);
      if(!foundPalette) throw new Error(`Palette with id: ${id} does not exits.`)
    
      const palette = generatePalette(foundPalette);
    
      return <Palette palette={palette} />;
    };
    

    Try the code above and see if it will throw that error

    Login or Signup to reply.
  2. Issue

    The issue is in the generatePalette where the code attempts to access properties of an undefined starterPalette function argument.

    export function generatePalette(starterPalette) { // <-- undefined
      let newPalette = {
        paletteName: starterPalette.paletteName, // <-- throws error
        id: starterPalette.id,
        emoji: starterPalette.emoji,
        colors: {},
      };
    
      ...
    

    Solutions

    You can resolve in several ways, here are a couple trivial suggestions:

    1. Provide fallback initial value to generatePalatte function:

      ...
      import seedColors from "./seedColors";
      ...
      
      export function generatePalette(starterPalette = seedColors[0]) {
        const newPalette = {
          paletteName: starterPalette.paletteName,
          id: starterPalette.id,
          emoji: starterPalette.emoji,
          colors: {},
        };
      
        ...
      
    2. Realize that Array.prototype.find potentially returns undefined if there are no matches, so it could return a defined fallback value.

      const findPalette = (id) => {
        return seedColors.find((palette) => palette.id === id) ?? seedColors[0];
      };
      
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search