7

親クラス内でその高さを使用できるように、ステートレスな子コンポーネントの高さを取得しようとしていますが、次のエラーが発生しています。Invariant Violation: Stateless function components cannot have refs.

簡素化されたコード

親クラス

class App extends React.Component {
  componentDidMount() {
    console.log(this.header);
  }
  render() {
    return (
      <Child ref={component => this.header = component} />
    )
  }
}

const Child = () => (
  <header ref="header">
    Some text  
  </header>
)

これを行う方法はありますか?

エラーのある Codepenへのリンクを次に示します。

アップデート:

実際のコード/コンテキスト

だから私は現在、次のようなヘッダーコンポーネントを持っています:

export const Header = ({dateDetailsButton, title, logo, backButton, signUpButton, inboxButton, header}) => (
    <header header className="flex flex-row tc pa3 bb b--light-gray relative min-h-35 max-h-35">
      {signUpButton ? <Link to="/edit-profile-contact" href="#" className="flex z-2"><AddUser /></Link> : null }
      {backButton ? <BackButton className="flex z-2" /> : null }
      <h1 className={logo ? "w-100 tc dark-gray lh-solid f4 fw5 tk-reklame-script lh-solid ma0" : "w-100 tc dark-gray lh-solid f4 fw4 absolute left-0 right-0 top-0 bottom-0 maa h1-5 z-0"}>{title}</h1>
      {dateDetailsButton ? <Link to="/date-details" className="absolute link dark-gray right-1 top-0 bottom-0 maa h1-5 z-2">Details</Link> : null }
      {inboxButton ? <Link to="/inbox" href="#" className="flex mla z-2"><SpeechBubble /></Link> : null}
    </header>
)

場合によっては、このヘッダーにロジックを追加してアニメーション化する必要があります (たとえば、ユーザーがスクロールしたときのホームページで、特定のポイントを過ぎてスクロールしたときに固定されるようにヘッダーをアニメーション化しています。 )。

私が以前にこれを行った方法は、特定の機能 (上記のように) を持つヘッダーと持たないヘッダーに別のクラスを用意することでした。しかし、コードを DRY に保つために、ヘッダーを分離して独自の機能的なステートレス コンポーネントにし、スティッキー ヘッダー機能を提供するクラスにラップするようにしました。

そのためのクラスは次のとおりです。

export default class FeedHeader extends React.Component {

    constructor(props) {
        super(props);
        this.handleScroll = this.handleScroll.bind(this);
        this.state = {
            scrolledPastHeader: null,
            from: 0,
            to: 1,
        }
    }

    componentDidMount() {
        window.addEventListener('scroll', this.handleScroll);
        this.setState({navHeight: this.navHeight.offsetHeight});
    }

    componentWillUnmount() {
        window.removeEventListener('scroll', this.handleScroll);
    }

    handleScroll(e) {
        const { navHeight, scrolledPastHeader } = this.state;
        const wy = document.body.scrollTop;
        if (wy < navHeight) this.setState({scrolledPastHeader: null})
        else if (wy > navHeight && wy < 100) {
            this.setState({scrolledPastHeader: false})
        }
        else this.setState({scrolledPastHeader: true})
    }

    getMotionProps() {
        const { scrolledPastHeader } = this.state;

        return scrolledPastHeader === false ?
        {
            style: {
                value: this.state.from
            }
        }
        : {
            style: {
                value: spring(this.state.to)
            }
        }
    }

    render() {
        const { brand, blurb } = this.props;
        const { scrolledPastHeader } = this.state;
        return (
            <Motion {...this.getMotionProps()}>
                {({value}) => {
                    return (
                        <Header ref="child" title={this.props.title} backButton={false} signUpButton inboxButton logo/>
                    );
                }}
            </Motion>
        )
    }
}

これがこの特定の問題のコンテキストです。これで物事がもう少し明確になることを願っています。

Ps コンテキストが不足していて申し訳ありません。答えは見た目よりも簡単だと思いました。

4

2 に答える 2