React.js关于从组件中侦听窗口事件的最佳实践

时间:2015-10-01 20:50:09

标签: javascript reactjs

我根据它们在视口中的位置设置了几个React.js组件的动画。如果组件位于视口中,则将不透明度设置为1,如果它不在视口中,则将其不透明度设置为0.我使用getBoundingClient()的{​​{1}}和top属性确定组件是否在视口中。

ComponentA显示了其他B,C和D组件所遵循的模式。他们每个人都在监听bottom滚动事件。

这是“React”方法,每个组件必须向window添加一个事件监听器吗?同一窗口上有多个滚动事件侦听器?

或者,通过在window所有者组件中将滚动事件侦听器添加到窗口,有没有更好的方法?那么ownee子组件是否仍然能够使用Home知道它们在DOM中的位置?

getBoundingClient()

4 个答案:

答案 0 :(得分:32)

有几种不同的方法可以做到这一点。一个是通过作文:

var React = require("react");
var _ = require("underscore");

var ScrollWrapper = React.createClass({
    propTypes: {
        onWindowScroll: React.PropTypes.func
    },

    handleScroll: function(event) {
        // Do something generic, if you have to
        console.log("ScrollWrapper's handleScroll");

        // Call the passed-in prop
        if (this.props.onWindowScroll) this.props.onWindowScroll(event);
    },

    render: function () {
        return this.props.children;
    },

    componentDidMount: function() {
        if (this.props.onWindowScroll) window.addEventListener("scroll", this.handleScroll);
    },

    componentWillUnmount: function() {
        if (this.props.onWindowScroll) window.removeEventListener("scroll", this.handleScroll);
    }
});

var ComponentA = React.createClass({
    handleScroll: function(event) {
        console.log("ComponentA's handleScroll");
    },

    render: function() {
        return (
            <ScrollWrapper onWindowScroll={this.handleScroll}>
                <div>whatever</div>
            </ScrollWrapper>
        );
    }
});

现在,您可以将通用逻辑放在ScrollWrapper组件中,然后突然变得可重用。您可以创建一个ComponentB,就像ScrollWrapper一样呈现ComponentA

为了满足你的榜样,也许你必须从ScrollWrapper传递ComponentA一些额外的道具。也许你会传给它一个包含ref实例的道具来调用你的逻辑。您甚至可以传递一些选项或参数来自定义补间或边界。我没有编写任何代码,因为我认为你会理解它,并且能够使用我提供的基础为你自己定制/编写它。

实现此类目标的另一种方法是通过Mixin。虽然,有很多关于Mixins是好还是坏的讨论,他们甚至可能在未来被React弃用?你可以阅读一下这个,然后自己决定你的想法。

答案 1 :(得分:16)

这是一个更简单的代码段,可以根据需要运行。您缺少this绑定,因此,当您执行window.addEventListener('scroll', this.handleScroll);时,您实际上将this指向窗口对象。

相反,您需要在构造函数中绑定它。希望它

class Home extends Component {
  constructor(props) {
    super(props)
    this.handleScroll = this.handleScroll.bind(this);
  }
  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
  }
  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }
  handleScroll(e) {
    console.log('scroll event');
    console.log(e);
  }

  render() {
    return (
     <div>
       <ComponentA />
       <ComponentB />
       <ComponentC />
       <ComponentD />
     </div>
    );
  }
}

另一个选项如下,两个选项都应该有效:)

class Home extends Component {
  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll.bind(this));
  }
  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll.bind(this));
  }
  handleScroll(e) {
    console.log('scroll event');
    console.log(e);
  }

  render() {
    return (
     <div>
       <ComponentA />
       <ComponentB />
       <ComponentC />
       <ComponentD />
     </div>
    );
  }
}

答案 2 :(得分:11)

这里是带有useEffect挂钩的实用样式:

$role = DB::table('role_user')->select('role_id')->where('company_id', $cp)->get();
foreach ($role as $key) {
    $role = $key;
}

$roles = Role::where('id', $role->role_id)->get();

答案 3 :(得分:2)

我肯定会添加一个事件监听器/组件。意识形态是将具有可重复使用的分离组件放置在应用程序中的“任何位置” - 以最大限度地减少代码冗余。

因此,您按照合作伙伴保留事件列表的方法是有效的。