从父组件访问React组件子元素属性

49

我目前正在设计一个用JavaScript和ReactJS编写的游戏引擎界面。

如果一个游戏对象有纹理,那么纹理的来源将显示在游戏对象上。为了使其正常工作,游戏对象需要引用纹理或更具体地说是纹理的来源。我希望有以下类似的JSX代码片段:

<GameObject>
  <Texture source="myimage.png" />
</GameObject>

我能提供的最佳解决方案是将纹理作为prop来传递,就像这样:

<GameObject texture={<Texture source="myimage.png" />} />

如果游戏引擎特定的术语让你感到有点困惑,可以将其视为按钮组件内的标题组件,其中标题组件具有特定数据,该数据需要按钮访问。

我的问题归结为:是否可能在孩子被挂载后访问其属性而不使用hack或成为反模式?


2
请查看react-router代码,了解它如何解析子元素:https://github.com/rackt/react-router/blob/master/modules/createRoutesFromReactChildren.js - WiredPrairie
3
被引用的函数现在在模块RouteUtils中。 - blackwood
3
我觉得这会有所帮助,但由于链接现在已经失效,信息也就丢失了。 - ms007
请在您的回答中至少提供摘要,而不仅仅是链接。链接应该只提供额外的细节。这里的所有链接现在都已失效。 - Darko Maksimovic
1
这是完整的URL https://github.com/remix-run/react-router/blob/v5.3.4/packages/react-router/modules/Switch.js - Lonli-Lokli
显示剩余2条评论
5个回答

44
由于评论中的链接已经失效,我在此附上一个链接到当前react-router Switch模块实现的链接,其中子级被解析(请参见render()函数)。此外,在这个教程视频中,作者从父组件访问子组件。
为了避免再次遇到链接过期的问题,以下是如何访问上面示例中父级组件的子组件属性的代码(受react-routerSwitch启发):
(在GameObject内部)
const { children } = this.props

React.Children.forEach(children, element => {
  if (!React.isValidElement(element)) return

  const { source } = element.props

  //do something with source..
})

1
规范的URL可以更好地防止链接被轻易破坏(当然最好直接在SO上发布代码)。 - GTF
这是完整的URL https://github.com/remix-run/react-router/blob/v5.3.4/packages/react-router/modules/Switch.js - Lonli-Lokli

3
您可以直接使用this.props.texture.props来访问。我不知道这是否是一种反模式,但我认为这不是一种常见的模式。如果您想要访问特定的prop,则它看起来确实可能会破坏封装。
您不必将元素作为prop传递以获取对其的引用。您可以通过this.props.children访问子元素。
有关更多信息,请参阅文档

1
这绝对是一种反模式。如果你需要从子组件中获取某些数据,那么在父组件中使用 state 并将其作为 prop 传递给子组件可能更好。 - Hozefa
1
我认为这不是反模式来反应本身。然而,它确实是一种反模式,与React一起使用的流行数据流模式(如Redux和Flux)相结合。它会破坏数据的单向流动。 - V Maharajh

1
这是你想要的那种东西吗?

const Game = ({
  children
}) => {
  // small hack to turn single child, into array
  if (!children.length) {
    children = [children];
  }

  children.map((child, i) => {
    // now have access to props.source in parent
    console.log(child.props.source);
  })

  return ( < div > {
    children
  } < /div>
  );  
}

const Texture = ({source}) => {
  return (
    <div>Texture: {source}</div > );
}

ReactDOM.render(( < Game >
      < Texture source = "thing.png" / >
      < Texture source = "other.png" / >
      < /Game>
), document.getElementById('game'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='game'></div>

实际上有点混乱。

我个人会给Game一个纹理数组,让它自己加载。

或者完全解耦GameTexture,这样数据只朝一个方向流动。


0

纹理需要拥有什么,它的父级应该是什么?

你能定义一个拥有并且是纹理父级的游戏对象吗?例如:

<GameObject textureSoure='myimage.png' />

那么 GameObject 在 render() 中渲染纹理吗?

return <....>
   <Texture source={ this.props.textureSource } />
     </....>

0

解决同样问题的另一种方法可能是:

将需要有条件从子级访问的日期添加到父级属性中...

这个方法永远不会出错。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接