【问题标题】:How to get rendered JSX in React?如何在 React 中渲染 JSX?
【发布时间】:2020-06-28 03:58:27
【问题描述】:

想象一个Container 组件使用指定的height 渲染div,例如:

<Container height="80">
  Hello World
</Container>

MyHeader 组件,它使用特定的height 呈现Container,例如:

function MyHeader() {
  return (
    <Container height="100">
      Header content goes here
    </Container>
  );
}

现在,我想实现一个如下所示的Fixed 组件:

<Fixed>
  <Fixed.Item>
    <MyHeader />
  </Fixed.Item>
  <Fixed.Content>
    Some content goes here
  </Fixed.Content>
</Fixed>

在渲染 Fixed.Content 时,我想自动将其偏移设置为 100px(因为 MyHeader 是 100px 高)。

有没有办法让Fixed 组件获取MyHeaderheight,以便将其传递给Fixed.Content

有没有更好的自动化方法?

注意:使用useEffect(或componentDidMount)不是一个选项,因为我希望它在服务器渲染环境中工作。

【问题讨论】:

  • 你能把高度作为道具传递给Fixed中的MyHeader吗?
  • 并非如此。只有MyHeader 知道它实际呈现的内容及其height。我们可以在这里假设的是,它总是渲染一个带有 height 属性集的 Container
  • 也许尝试使用refMyHeader 然后你可以使用clientHeight 属性从那里抵消你的Fixed.Content
  • 是否有任何理由需要使用偏移量将内容放置在标题下方?只是将它们堆叠在一个块中或弹性显示中是一种选择吗?
  • 我希望标题是固定的/粘性的。

标签: reactjs jsx


【解决方案1】:

通常,您希望数据从父母流向孩子。如果这不适合您,您可以使用上下文:https://reactjs.org/docs/context.html。特别是查看https://reactjs.org/docs/context.html#updating-context-from-a-nested-component。在您的情况下,MyHeader 可能是您的上下文的 Consumer 并使用其高度更新它,Fixed.Content 也将是使用该值作为其偏移量的消费者。但总的来说,我会说你想要做的事情有点不自然。

【讨论】:

  • 使用上下文示例不起作用,因为我希望它在不存在第二个渲染的服务器渲染环境中工作。
【解决方案2】:

您可以为此使用 refs。

要解决您的具体问题,首先将您的&lt;Container&gt; 组件转换为类组件,以便能够为其设置引用。

然后使用React.forwardRef将MyHeader组件中的ref转发到&lt;Container&gt;组件:

const MyHeader = React.forwardRef((props, ref) => {
  return (
    <Container ref={ref} height={100}>
      Header content goes here
    </Container>
  );
});

最后,在您的组件中创建一个 ref 挂钩,用于呈现 &lt;Fixed&gt; 组件并将 ref 传递给 &lt;MyHeader&gt; 组件。然后,您还可以使用 ref 设置 &lt;Fixed.Content&gt; 组件的高度(或任何您想要设置的),如下所示:

function App () {
  const headerRef = React.useRef(null)
  return (
      <Fixed>
        <Fixed.Item>
          <MyHeader ref={headerRef} />
        </Fixed.Item>
        <Fixed.Content height={headerRef.current && headerRef.current.props.height}>
          Some content goes here
        </Fixed.Content>
      </Fixed>
  )
}

这似乎只渲染一次&lt;App&gt; 组件,因此它也应该适用于服务器端渲染。以如下代码sn-p为例:https://codesandbox.io/s/get-height-from-header-gvvlo

【讨论】:

    【解决方案3】:

    您可以使用 React Test Renderer 将 React Node 呈现为可检查的对象树。

    import TestRenderer from 'react-test-renderer';
    
    const height = TestRenderer.create(<MyHeader />).toTree().rendered.props.height
    

    这样,你可以在没有第二次渲染的情况下获得它的高度。

    【讨论】:

      【解决方案4】:
      function Container(props) {
        return (
          <div style={{height:props.height}}>
             your content
          </div>
        );
      }
      

      您需要将高度作为可以动态变化的道具传递给Container

      function MyHeader() {
        return (
          <Container height="100px">
            Header content goes here
          </Container>
        );
      }
      

      对于固定的,您还需要通过将高度放在变量中来将其作为道具传递,例如:

      function TopBar() {
        let height = '100px'
        return (
           <>
             <MyHeader height={height} />
             <FixedComponent height={height} />
           </> 
        );
      }
      

      【讨论】:

      • 问题的重点是避免按照您的建议行事。我想自动化height 知识并让Fixed.Content 根据Fixed.Item 中呈现的内容来解决这个问题。
      • 这种情况下需要得到header高度ele.style.height,可以在Fixed.Content中使用
      【解决方案5】:

      我认为您需要将高度道具从MyHeader 传递给Fixed。然后FixedFixed.Content。例如,您可以执行以下类似操作:

      MyHeader.jsx

      class MyHeader extends React.Component {
          constructor(props) {
              super(props)
              this.state = {
                  height: 100
              }
              this.props.setHeaderOffset(this.state.height)
          }
          render() {
              return (
                  <Container height={this.state.height}>
                  </Container>
              )
          }
      }
      

      Fixed.jsx

      class Fixed extends React.Component {
          constructor(props) {
              super(props)
              this.state = {
                  headerOffset: 0
              }
              this.setHeaderOffset = this.setHeaderOffset.bind(this)
          }
          setHeaderOffset(headerOffset) {
              this.setState({
                  headerOffset
              })
          }
          render() {
              return (
                  <>
                      <Item>
                          <MyHeader setHeaderOffset={this.setHeaderOffset} />
                      </Item>
                      <Content headerOffset={this.state.headerOffset}>
                          Some content goes here
                      </Content>
                  </>
              )
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-05-17
        • 2017-03-10
        • 1970-01-01
        • 2022-12-14
        • 2021-10-11
        • 2018-06-25
        • 2015-01-17
        • 2019-01-18
        相关资源
        最近更新 更多