【问题标题】:Using React Hooks, when I pass down a prop from parent to a child component, the prop in the child component is undefined使用 React Hooks,当我将 prop 从父组件传递到子组件时,子组件中的 prop 未定义
【发布时间】:2021-10-15 09:10:05
【问题描述】:

我想做什么?

我正在尝试设置一个对象数组,其中数组中的值取决于父组件。

目前尝试这样做的代码是什么?

以下是简化的不同文件:

// Parent.

export default function Parent() {
  const [filePaths, setFilePaths] = useState();

  useEffect(() => {
    var fileContent = JSON.parse(fs.readFileSync("./config.json"); // Reading from a JSON.
    var tempFilePaths = [];
    fileContent.FilePaths.forEach((file) => {
      tempFilePaths.push(file);
    });
    setFilePaths(tempFilePaths); // Contents of "config.js" is now in the "useState".
  }, []);

  return (
    <Child filePaths={filePaths}/>
  )
}
// Child.

export default function Child({filePaths}) {
  var links = [
    {
      path: filePaths[0].Link1,
    },
    {
      path: filePaths[0].Link2,
    },
  ]

  return (
    <div>Nothing here yet, but I would map those links to front-end links.</div>
  )
}
// config.json

{
  "url": "http:localhost:3000",
  "FilePaths": [
    {
      "Link1": "C:\Documents\Something",
      "Link2": "C:\Documents\SomethingElse"
    }
  ]
}

当我在子组件的return() 中渲染“filePaths”时,可以渲染“filePaths”,但我希望将“filePaths”设置为变量“links”。

我期望结果是什么?

我希望变量“links”在子组件中很好,能够在子组件中使用。

实际结果如何?

启动应用程序时,我得到一个TypeError: Cannot read property '0' of undefined.

我认为问题可能是什么?

我认为子组件在父组件没有完成useEffect() 的情况下呈现。我想知道是否有办法告诉子组件等待父组件完成,然后继续设置“链接”变量。

【问题讨论】:

  • filePaths 在父级中未定义,直到由setFilePaths(tempFilePaths);useEffect 挂钩中设置。似乎消费组件假定它已定义。请分享一个完整的代码示例来重现您的问题。

标签: javascript reactjs react-hooks state


【解决方案1】:

我认为您对方法调用顺序的猜测是正确的:

根据this,当你使用useEffect时,该方法在渲染后被调用,就像它是一个componentDidMount生命周期方法,由React official lifecycle diagramReact Documentation支持。这就是原因,因为 Child 组件中的 props.filePaths 未定义。

为避免这种情况,您应该尝试设置一个初始值(在 useState 方法中)。

类似于以下内容(可能将重复提取为函数):

// Parent.

export default function Parent() {

  var fileContent = JSON.parse(fs.readFileSync("./config.json"); // Reading from a JSON.
    var tempFilePaths = [];
    fileContent.FilePaths.forEach((file) => {
      tempFilePaths.push(file);
    });
  
  const [filePaths, setFilePaths] = useState(tempFilePaths);

  useEffect(() => {
    var fileContent = JSON.parse(fs.readFileSync("./config.json"); // Reading from a JSON.
    var tempFilePaths = [];
    fileContent.FilePaths.forEach((file) => {
      tempFilePaths.push(file);
    });
    setFilePaths(tempFilePaths); // Contents of "config.js" is now in the "useState".
  }, []);

  return (
    <Child filePaths={filePaths}/>
  )
}

【讨论】:

    【解决方案2】:

    filePaths 将是 undefined,因为您调用 useState() 时输入为空。

    有两个选项(你可以选择一个)来解决这个问题:

    1. useState()内初始化filePaths

    2. 如果filePaths 不为空/未定义,则返回Child 组件。

    export default function Parent() {
        const [filePaths, setFilePaths] = useState();
    
        useEffect(() => {
            var fileContent = JSON.parse(fs.readFileSync("./config.json"); // Reading from a JSON.
            var tempFilePaths = [];
            fileContent.FilePaths.forEach((file) => {
                tempFilePaths.push(file);
            });
            setFilePaths(tempFilePaths); // Contents of "config.js" is now in the "useState".
        }, []);
    
        return (
            // return the Child component if the filePaths is not null/undefined
            {filePaths && <Child filePaths={filePaths}/>}
        )
    }
    

    我个人更喜欢第二个,因为我们可以在filePaths 仍然为空/未定义时添加加载组件。

    【讨论】:

      【解决方案3】:

      你是对的,这就是为什么你应该改变你的子组件。它呈现 filePaths 是否已定义。

      尝试如下操作。

      export default function Child({filePaths}) {
        const [links, setLinks] = useState(filePaths);
        useEffect(()=>{
          setLinks(filePaths);
        },[filePaths])
      
        return (
          <div>Nothing here yet, but I would map those links to front-end links.</div>
        )
      }
      

      【讨论】:

        【解决方案4】:

        const [filePaths, setFilePaths] = useState();会将文件路径初始化为未定义。
        所以你可以先检查一下 if (!filePaths) return null 在父级中; 或在 useState 中设置 initState @见https://reactjs.org/docs/hooks-reference.html#lazy-initial-state

        const [filePaths, setFilePaths] = useState(()=> {
            var fileContent = JSON.parse(fs.readFileSync("./config.json");
            var tempFilePaths = [];
            fileContent.FilePaths.forEach((file) => {
              tempFilePaths.push(file);
            });
            return tempFilePaths;
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-09-14
          • 2018-04-26
          • 2021-11-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多