0

我编写了一个函数(最后一个代码片段),如果用户单击输入搜索之外的任何位置,它会隐藏输入搜索。

我现在要做的是当它隐藏时,它还应该清除输入中的文本。我尝试过 useState 并作为参数传递,我尝试过 useContext。但是,我尝试的任何方法似乎都不起作用。

应用程序.js 文件

import React, { useState } from 'react';
import { Helmet } from 'react-helmet'

// Components
import Header from './Components/Header.js';

// Globals
import { GlobalContext } from './Globals/GlobalContext.js';

const App =() => {
  // Variables
  const [searchText, setSearchText] = useState('');
  // Render
  return (
    <div className="app">
      <Helmet>
        <meta charSet="utf-8" />
        <title>LOG</title>
      </Helmet>
      <GlobalContext.Provider value={{ searchText, setSearchText }}>
        <Header />
      </GlobalContext.Provider>
    </div>
  );
}

export default App;

Header.js 文件

import React from 'react';

// Components
import HeaderTop from './HeaderComponents/HeaderTop.js';

const Header = () => {
  return (
    <header className="header">
      <HeaderTop />
    </header>
  )
}

export default Header;

HeaderTop.js 文件

import React, { useContext } from 'react';

// Globals
import { GlobalContext } from '../../Globals/GlobalContext.js';
import { useComponentVisible } from '../../Globals/index.js';

const HeaderTop = () => {
  // Variables
  const evSearchBtnName = "open-close-search-btn";
  const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false, evSearchBtnName);
  const { searchText, setSearchText } = useContext(GlobalContext);

  // functions
  const searchSubmit = (ev) => {
    ev.preventDefault();
    console.log("Use \"" + searchText + "\" for search library");
  }
  // Render
  return (
    <div className="div-header-content-top">
      <div className="div-header-top-left">
        <h1>LOG</h1>
        <div className="div-header-top-left-search-icon" name={evSearchBtnName} onClick={() => (setIsComponentVisible(!isComponentVisible))} />
        <form onSubmit={ev => searchSubmit(ev)}>
          <div ref={ref} style={isComponentVisible ? {width: "100%"} : {width: "0", overflow: "hidden"}}>
            <input type="search" name="searchText" placeholder="search..." onChange={ev => setSearchText(ev.target.value)} />
          </div>
          <button type="submit" name={evSearchBtnName} />
        </form>
      </div>
    </div>
  )
}

export default HeaderTop;

全局/index.js 文件

import { useComponentVisible } from "./Functions.js";

export { useComponentVisible }

Globals/Functions.js 文件

import { useState, useEffect, useRef, useContext } from 'react';

// Globals
import { GlobalContext } from './GlobalContext.js';

const useComponentVisible = (initialIsVisible, evTriggerBtnName="default-trg-btn") => {
  const { setSearchText } = useContext(GlobalContext);
  const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
  const ref = useRef(null);

  const handleClickOutside = (event) => {
    if (ref.current && isComponentVisible && !ref.current.contains(event.target) && (event.target.name ? event.target.name !== evTriggerBtnName : event.target.getAttribute('name') !== evTriggerBtnName)) {
      setSearchText(''); // <-------------------------- this is not working
      setIsComponentVisible(false);
    }
  };

  useEffect(() => {
    document.addEventListener('click', handleClickOutside, true);
    return () => {
      document.removeEventListener('click', handleClickOutside, true);
    };
    // eslint-disable-next-line
  }, [isComponentVisible]);

  return { ref, isComponentVisible, setIsComponentVisible };
}

export { useComponentVisible }

任何人都知道为什么setSearchText('');在最后一个代码片段中不起作用?

4

1 回答 1

1

我不认为你可以使用你的Context内部,useComponentVisible custom hook因为它实际上并没有被包裹:-

<GlobalContext.Provider value={{ searchText, setSearchText }}>
  <Header />
</GlobalContext.Provider>

双向尝试

  • 不知道哪一个对你有用

选项 1

所以,不仅仅是: -

  • 和,fields_false, evSearchBtnName
  • const { setSearchText } = useContext(GlobalContext);直接在您的调用和导入custom hook

你为什么不 ():-

  • 传递setSearchText给你的custom hook

  • HeaderTop.js

const HeaderTop = () => {
  const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false, evSearchBtnName, setSearchText);
  
  return ()
}
  • Globals/Functions.js:-
const useComponentVisible = (initialIsVisible, evTriggerBtnName="default-trg-btn", setSeacrhText) => {
  // don't need this anymore then
  // const { setSearchText } = useContext(GlobalContext);
  // ...something
}

选项 2

  • 创造新stateuseComponentVisible custom hook

  • 并用于useEffect检测HeaderTop.js所述的变化 state

  • Globals/Functions.js:-

// Globals
import { GlobalContext } from './GlobalContext.js';

const useComponentVisible = (initialIsVisible, evTriggerBtnName="default-trg-btn") => {
  const [searchText2, setSearchText2] = useState(''); // new custom state
  const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
  const ref = useRef(null);

  const handleClickOutside = (event) => {
    if (ref.current && isComponentVisible && !ref.current.contains(event.target) && (event.target.name ? event.target.name !== evTriggerBtnName : event.target.getAttribute('name') !== evTriggerBtnName)) {
      setSearchText2(''); // <-------------------------- this is not working
      setIsComponentVisible(false);
    }
  };

  useEffect(() => {
    document.addEventListener('click', handleClickOutside, true);
    return () => {
      document.removeEventListener('click', handleClickOutside, true);
    };
    // eslint-disable-next-line
  }, [isComponentVisible]);

  return { ref, isComponentVisible, setIsComponentVisible, searchText2};
}

export { useComponentVisible }
  • HeaderTop.js:-
const HeaderTop = () => {
  // Variables
  const evSearchBtnName = "open-close-search-btn";
  const { ref, isComponentVisible, setIsComponentVisible, searchText2 } = useComponentVisible(false, evSearchBtnName);
  const { searchText, setSearchText } = useContext(GlobalContext);

  // apply changes in searchText2
  useEffect(() => {
    setSearchText(searchText2)
  }, [searchText2])

  // functions
  const searchSubmit = (ev) => {
    ev.preventDefault();
    console.log("Use \"" + searchText + "\" for search library");
  }
  // Render
  return (
    <div className="div-header-content-top">
      <div className="div-header-top-left">
        <h1>LOG</h1>
        <div className="div-header-top-left-search-icon" name={evSearchBtnName} onClick={() => (setIsComponentVisible(!isComponentVisible))} />
        <form onSubmit={ev => searchSubmit(ev)}>
          <div ref={ref} style={isComponentVisible ? {width: "100%"} : {width: "0", overflow: "hidden"}}>
            <input type="search" name="searchText" placeholder="search..." onChange={ev => setSearchText(ev.target.value)} />
          </div>
          <button type="submit" name={evSearchBtnName} />
        </form>
      </div>
    </div>
  )
}

export default HeaderTop;
于 2020-12-02T01:06:52.463 回答