web-dev-qa-db-ja.com

スクロールに基づいてクラスを切り替えるReact JS

私はbootstrap 4ナビゲーションバーを使用しており、400ピクセルのダウンスクロールダウン後にバックグラウンドカラーを変更したいと考えています。反応ドキュメントを見ていて、onScrollを見つけましたが、それほど多くは見つかりませんでした。これに関する情報これまでのところ...

適切なイベントリスナーを使用しているかどうかや、高さの設定方法などがわかりません。

そして、私は実際にはインラインスタイルを設定していません...

  import React, { Component } from 'react';

   class App extends Component {

   constructor(props) {
    super(props);

      this.state = {  scrollBackground: 'nav-bg' };
      this.handleScroll = this.handleScroll.bind(this);
   }


   handleScroll(){
      this.setState ({
         scrollBackground: !this.state.scrollBackground
       })
    }

 render() {
 const scrollBg = this.scrollBackground ? 'nav-bg scrolling' : 'nav-bg';

 return (
   <div>

       <Navbar inverse toggleable className={this.state.scrollBackground} 
                                  onScroll={this.handleScroll}>
        ...
      </Navbar>

    </div>
   );
  }
}

export default App;
13
Fernando B

スクロールリスナーを追加する1つの方法は、componentDidMount()ライフサイクルメソッドを使用することです。次の例はあなたにアイデアを与えるでしょう:

import React from 'react';
import { render } from 'react-dom';

class App extends React.Component {
  state = {
    isTop: true,
  };

  componentDidMount() {
    document.addEventListener('scroll', () => {
      const isTop = window.scrollY < 100;
      if (isTop !== this.state.isTop) {
          this.setState({ isTop })
      }
    });
  }
  render() {
    return (
      <div style={{ height: '200vh' }}>
        <h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
      </div>
    );
  }
} 

render(<App />, document.getElementById('root'));

これにより、scrollYの位置が100以上のときにテキストが「下にスクロール」から「上にスクロール」に変わります。

編集:各スクロールの状態を更新しすぎるのを避けます。ブール値が変更されたときにのみ更新します。

16
glennreyes

2019年にこの質問を読むである皆さんのために、@ glennreyesの回答を取り、React Hooksを使用してそれを書き直しました。

  const [scroll, setScroll] = useState(0)

  useEffect(() => {
    document.addEventListener("scroll", () => {
      const scrollCheck = window.scrollY < 100
      if (scrollCheck !== scroll) {
        setScroll(scrollCheck)
      }
    })
  })

seStateには2つの要素の配列があります。最初はstate object、次にそれを更新する関数です。

seEffectcomponentDidmountを置き換えるのに役立ちます。この場合は不要なので、現在記述されている関数はクリーンアップを実行しません。

クリーンアップが不可欠であるとわかった場合は、seEffect内の関数を返すだけです。

包括的に読むことができます こちら

更新:

もしあなたがそれをmodularにしたいと感じたならclean upさえするなら、あなたはこのようなことをすることができます:

  1. 以下のようにカスタムフックを作成します。

    import { useState, useEffect } from "react"
    
    export const useScrollHandler = () => {
    // setting initial value to true
    const [scroll, setScroll] = useState(1)
    
    // running on mount
    useEffect(() => {
      const onScroll = () => {
        const scrollCheck = window.scrollY < 10
        if (scrollCheck !== scroll) {
          setScroll(scrollCheck)
        }
      }
    
    // setting the event handler from web API
    document.addEventListener("scroll", onScroll)
    
    // cleaning up from the web API
     return () => {
       document.removeEventListener("scroll", onScroll)
      }
    }, [scroll, setScroll])
    
    return scroll
    
    }
    
  2. 任意のコンポーネント内で呼び出す見つかります:

    Const component = () => {
    
    // calling our custom hook
    const scroll = useScrollHandler()
    
    ....... rest of your code
    
    }
    
6
Pouya Ataei

それは良いです

import React from 'react';
import { render } from 'react-dom';

class App extends React.Component {
    constructor(props) {
    super(props);

    this.state = {
      isTop: true
    };
    this.onScroll = this.onScroll.bind(this);
  }

  componentDidMount() {
    document.addEventListener('scroll', () => {
      const isTop = window.scrollY < 100;
      if (isTop !== this.state.isTop) {
        this.onScroll(isTop);
      }
    });
  }

  onScroll(isTop) {
    this.setState({ isTop });
  }

  render() {
    return (
      <div style={{ height: '200vh' }}>
        <h2 style={{ position: 'fixed', top: 0 }}>Scroll {this.state.isTop ? 'down' : 'up'}!</h2>
      </div>
    );
  }
} 

render(<App />, document.getElementById('root'));
3
amirhossein693

私のユースケースでは、@ PouyaAtaeiの回答を少し変更しました。

 import { useState, useEffect } from "react"

// Added distance parameter to determine how much 
// from the top tell return value is updated.
// The name of the hook better reflects intended use.
export const useHasScrolled = (distance = 10) => {

// setting initial value to false
const [scroll, setScroll] = useState(false)

// running on mount
useEffect(() => {
  const onScroll = () => {
// Logic is false tell user reaches threshold, then true after.
     const scrollCheck = window.scrollY >= distance;
    if (scrollCheck !== scroll) {
      setScroll(scrollCheck)
    }
  }

// setting the event handler from web API
document.addEventListener("scroll", onScroll)

// cleaning up from the web API
 return () => {
   document.removeEventListener("scroll", onScroll)
  }
}, [scroll, setScroll])

return scroll

}
};

フックを呼び出す:

Const component = () => {

// calling our custom hook and optional distance agument.
const scroll = useHasScrolled(250)

}
0
wildair

これは、ランダムなページ要素をスクロールして表示および非表示にするための、別のテイク/私のテイクオンフックアプローチです。

Dan Abramovの投稿はこちら

この CodeSandboxデモ で完全な動作例を確認できます。

次に、useScrollカスタムフックのコードを示します。

import React, { useState, useEffect } from "react";

export const useScroll = callback => {
  const [scrollDirection, setScrollDirection] = useState(true);

  const handleScroll = () => {
    const direction = (() => {
      // if scroll is at top or at bottom return null,
      // so that it would be possible to catch and enforce a special behaviour in such a case.
      if (
        window.pageYOffset === 0 ||
        window.innerHeight + Math.ceil(window.pageYOffset) >=
          document.body.offsetHeight
      )
        return null;
      // otherwise return the direction of the scroll
      return scrollDirection < window.pageYOffset ? "down" : "up";
    })();

    callback(direction);
    setScrollDirection(window.pageYOffset);
  };

  // adding and cleanning up de event listener
  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  });
};

そして、このフックは次のように消費されます:

  useScroll(direction => {
    setScrollDirection(direction);
  });

このカスタムフックを使用する完全なコンポーネント:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import CustomElement, { useScroll } from "./element";
import Scrollable from "./scrollable";

function Page() {
  const [scrollDirection, setScrollDirection] = useState(null);

  useScroll(direction => {
    setScrollDirection(direction);
  });

  return (
    <div>
      {/* a custom element that implements some scroll direction behaviour */}
      {/* "./element" exports useScroll hook and <CustomElement> */}
      <CustomElement scrollDirection={scrollDirection} />
      {/* just a lorem ipsum long text */}
      <Scrollable />
    </div>
  );
}

const rootElement = document.getElementById("root");

ReactDOM.render(<Page />, rootElement);

そして最後に、CustomElementのコード:

import React, { useState, useEffect } from "react";

export default props => {
  const [elementVisible, setElementVisible] = useState(true);
  const { scrollDirection } = props;

  // when scroll direction changes element visibility adapts, but can do anything we want it to do
  // U can use ScrollDirection and implement some page shake effect while scrolling
  useEffect(() => {
    setElementVisible(
      scrollDirection === "down"
        ? false
        : scrollDirection === "up"
        ? true
        : true
    );
  }, [scrollDirection]);

  return (
    <div
      style={{
        background: "#ff0",
        padding: "20px",
        position: "fixed",
        width: "100%",
        display: `${elementVisible ? "inherit" : "none"}`
      }}
    >
      element
    </div>
  );
};
0
Sergiu Dogotaru