首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >addEventListener在反应中为空

addEventListener在反应中为空
EN

Stack Overflow用户
提问于 2017-03-01 12:43:52
回答 4查看 9.3K关注 0票数 4

我正在使用React创建一个搜索功能。我以前用过这种方法,但没有反应,而且起了作用。现在,它在控制台中出现了一个错误:"Uncaught :无法读取属性'addEventListener‘of null“。这和它的反应有关吗?我该怎么解决这个问题?

代码语言:javascript
运行
复制
<body>
<div id="searching"></div>
<script type="text/babel">
    class SearchBox extends React.Component { render(){ return(
    <form>
        <input type="text" className="searchbox" />
    </form>) } } ReactDOM.render(
    <SearchBox />, document.getElementById("searching"));
</script>

JS

代码语言:javascript
运行
复制
const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json';
const repositories = [];

fetch(endpoint)
.then(blob => blob.json())
.then(data => repositories.push(...data));

function findMatches(wordToMatch, repositories) {
return repositories.filter(place => {

    const regex = new RegExp(wordToMatch, "gi");
    return place.city.match(regex) || place.state.match(regex);
    });
};

function displayMatches() {
const matchArray = findMatches(this.value, repositories);
const html = matchArray.map(place => {
    const regex = new RegExp(this.value, "gi");
    const cityName = place.city.replace(regex, `<span class="hl">${this.value}</span>`);
    const stateName = place.state.replace(regex, `<span class="hl">${this.value}</span>`);
    return `
  <li>
  <span class="name">${cityName}, ${stateName}</span>
  <span class="population">${numberWithCommas(place.population)}</span>
  </li>
  `;
}).join('');
console.log(matchArray);
suggestions.innerHTML = html;
};

const searchInput = document.querySelector(".searchbox");
const suggestions = document.querySelector(".suggestions");

searchInput.addEventListener("change", displayMatches);
searchInput.addEventListener("keyup", displayMatches);
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-03-01 12:56:18

通常情况下,将ReactJS与非ReactJS的做事方式相结合是个坏主意。React有一种非常特殊的处理事件的方法,直接调用addEventListener()也不太好。当您调用addEventListener()时,它有时会工作的可能性很小,但是您真的不应该依赖它。

您不应该将两者混合在一起的原因是,React可以在任何时候任意重建DOM :任何时候发生状态更改时,React都可以删除DOM元素并创建新的元素,而不是您的元素。你既不知道也不关心元素何时呈现,这是反应美的一部分。

那么你是如何处理这些事件的呢?在创建元素时,您必须使用像onChangeonKeyUp这样的属性,以一种类似于传统的方式将它们连接起来。(在幕后,React将在正确的时间使用addEventListener,但您从未真正注意到这种情况的发生。)

那么,修改后的代码版本的结构可能如下所示:

代码语言:javascript
运行
复制
class SearchBox extends React.Component {

    constructor(props) {
        super(props);

        // This binding is necessary to make `this` work in the callback
        this.onKeyUp = this.onKeyUp.bind(this);
        this.onChange = this.onChange.bind(this);
    }

    onChange(event) {
        ...
    }

    onKeyUp(event) {
        ...
    }

    render() {
        return(
            <form>
                <input type="text" className="searchbox" onChange={this.onChange} onKeyUp={this.onKeyUp} />
            </form>
        );
    }
}

ReactDOM.render(
    <SearchBox />,
    document.getElementById("searching")
);

正如您所看到的,整个代码的结构是不同的。React不仅仅是一种轻松地发出HTML元素的方法:它是一个基于组件的微框架,您可以围绕这个框架来设计整个UI。

票数 7
EN

Stack Overflow用户

发布于 2017-03-01 13:07:32

我不同意肖恩的看法。使用本机函数是可以的,实际上有时您必须这样做。

出现此错误的原因是脚本试图将侦听器添加到不存在的DOM节点:当侦听器脚本执行时,您的输入元素尚未被刷新到DOM。这就是为什么当您需要以这种方式访问一个转义口时,您应该在组件内部,在compnentDidMount中这样做,并且只有当一个子节点需要在一个完全不连接的父DOM节点上侦听时才这样做--例如,这个节点可能在其他反应性子树yiur组件所属的外部。这保证了您试图查找的节点已经存在。

尽管如此,以这种方式使用本机函数是一个逃避舱口,在95%的常见用例中应该也可以避免。您应该使用更多的惯用方式,要么将状态提升到更高级别的组件,要么在真正需要时使用ref。

票数 3
EN

Stack Overflow用户

发布于 2020-05-14 18:42:49

我同意肖恩的观点。本机java和ReactJS有不同的生命周期来处理事件。我在增加一些使用钩子的人。您可以使用useEffect和useRef添加自定义钩子。

  1. 将事件处理程序创建为Ref,并在使用useEffect初始化时将其绑定
  2. 在useEffect中用目标元素和侦听器绑定事件。

下面是创建useEventListener自定义钩子的示例代码。我从https://usehooks.com/useEventListener/得到了这个示例代码

代码语言:javascript
运行
复制
function useEventListener(eventName, handler, element = window){
  // Create a ref that stores handler
  const savedHandler = useRef();

  // Update ref.current value if handler changes.
  // This allows our effect below to always get latest handler ...
  // ... without us needing to pass it in effect deps array ...
  // ... and potentially cause effect to re-run every render.
  useEffect(() => {
    savedHandler.current = handler;
  }, [handler]);

  useEffect(
    () => {
      // Make sure element supports addEventListener
      // On 
      const isSupported = element && element.addEventListener;
      if (!isSupported) return;

      // Create event listener that calls handler function stored in ref
      const eventListener = event => savedHandler.current(event);

      // Add event listener
      element.addEventListener(eventName, eventListener);

      // Remove event listener on cleanup
      return () => {
        element.removeEventListener(eventName, eventListener);
      };
    },
    [eventName, element] // Re-run if eventName or element changes
  );
};
export default useEventListener;
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42532087

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档