英文:
Getting id with useParams (react router dom v6.11.0
问题
我正在跟随Colt Steele的React课程。不幸的是,这门课程已经过时,所以我选择使用函数组件而不是基于类的组件。
目前,我遇到了一个我不理解的问题。我将展示我的代码和错误消息。
App.js
```jsx
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>
    </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" },
    ],
  },
  //...
];
我尝试过查看findPalette和generatePalette函数以及调色板组件,但除了这个错误外,我还没有取得任何结果。
<details>
<summary>英文:</summary>
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. 
```lang-none
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" },
    ],
  },
  ...
I've tried looking at the findPalette and generatePalette functions, at the palette component but I haven't resulted in anything but this error.
答案1
得分: 1
你的问题出在PaletteWrapper:
const PaletteWrapper = () => {
  const { id } = useParams();
  const foundPalette = findPalette(id);
  if (!foundPalette) throw new Error(`ID为${id}的调色板不存在。`);
  const palette = generatePalette(foundPalette);
  return <Palette palette={palette} />;
};
尝试使用上述代码,看看是否会抛出错误。
英文:
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
答案2
得分: 0
问题
问题出在 generatePalette 函数中,代码试图访问未定义的 starterPalette 函数参数的属性。
export function generatePalette(starterPalette) { // <-- undefined
  let newPalette = {
    paletteName: starterPalette.paletteName, // <-- throws error
    id: starterPalette.id,
    emoji: starterPalette.emoji,
    colors: {},
  };
  ...
解决方案
您可以通过多种方式解决这个问题,以下是一些简单的建议:
- 
为
generatePalette函数提供默认初始值:... import seedColors from "./seedColors"; ... export function generatePalette(starterPalette = seedColors[0]) { const newPalette = { paletteName: starterPalette.paletteName, id: starterPalette.id, emoji: starterPalette.emoji, colors: {}, }; ... - 
请注意,如果没有匹配项,
Array.prototype.find可能会返回undefined,因此它可以返回一个定义的备用值。const findPalette = (id) => { return seedColors.find((palette) => palette.id === id) ?? seedColors[0]; }; 
英文:
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:
- 
Provide fallback initial value to
generatePalattefunction:... import seedColors from "./seedColors"; ... export function generatePalette(starterPalette = seedColors[0]) { const newPalette = { paletteName: starterPalette.paletteName, id: starterPalette.id, emoji: starterPalette.emoji, colors: {}, }; ... - 
Realize that
Array.prototype.findpotentially returnsundefinedif there are no matches, so it could return a defined fallback value.const findPalette = (id) => { return seedColors.find((palette) => palette.id === id) ?? seedColors[0]; }; 
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论