简体   繁体   English

Apollo React 为什么不能在 UseEffect 钩子内查询

[英]Apollo React Why Can't Query inside UseEffect hook

I am just learning about Apollo-React but I couldn't make graphql request我只是在学习 Apollo-React,但我无法发出 graphql 请求

This is how I do without Apollo这就是我没有阿波罗的方式

const Search = () => {
    const [searchedText, setSearchedText] = React.useState('')
    const [suggestions, setSuggestions] = React.useState([])
    const [selected, setSelected] = React.useState(null)

    const debounceHandler = (searchedText) => debounce(() => {
        sendQuery(`{search(str:"${searchedText}") {name}}`).then(({search}) => {
            if (!search) return
            setSuggestions(search)
        })
    }, 500)

    const handleInputChange = async (e) => {
        if(e.key === 'Enter') {
            const name = e.target.value
            sendQuery(`{getPokemon(str:"${name}"){name, image}}`).then(({getPokemon}) => {
                setSelected(getPokemon)
            })
        }
        debounceHandler(searchedText)()
    }

   return (
    <div>
            <h1>Pokemon Search</h1>
            <input type="text" value={searchedText} onChange={(e) => setSearchedText(e.target.value)} onKeyUp={(e) => handleInputChange(e)} style={{width:'100%'}} />
            <hr />
            <div>
                {selected ? <PokemonProfile selected={selected} /> : suggestions.map(({name}) => (
                    <ShowSuggestion name={name} searchedText={searchedText} setSelected={setSelected}/>
                )) }
            </div>
    </div>
    )
}

Now without my own sendQuery function, I want to use Apollo's useQuery hook.现在没有我自己的 sendQuery 函数,我想使用 Apollo 的 useQuery 钩子。

const GET_POKEMON = gql`
    query getPokemon ($str: String!) {
        getPokemon(str: $str) {
            name
            image
        }
    }
`;

const SEARCH = gql `
query search($str: String!) {
    search(str:$str) {
      name
    } 
  }
`;

These are my queries and results correctly on the playground.这些是我在操场上正确的查询和结果。 Now I write Search function again.现在我再次编写搜索功能。 I say whenever searchedText changes (WHen user types in), query Search and set the returning data as suggestions.我说每当 searchedText 更改时(当用户输入时),查询搜索并将返回的数据设置为建议。 Whenever user hits enter, I want to query the Pokemon from backend and set it as selected.每当用户按下回车键时,我想从后端查询 Pokemon 并将其设置为选中状态。


const Search = () => {
    const [searchedText, setSearchedText] = React.useState(null)
    const [suggestions, setSuggestions] = React.useState([])
    const [selected, setSelected] = React.useState(null)
    
    React.useEffect(() => {
        const { data } = useQuery(SEARCH, {
            variables: {  "str": searchedText },
            pollInterval: 500,
        });

        if (data) {
            setSuggestions(data)
          }

    }, [searchedText])


    const fetchAndSelect = name => {
        setSearchedText('')
        const { pokemon } = useQuery(GET_POKEMON, {
            variables: {
                "str": name
            }
        })

        setSelected(pokemon)
    }



    const handleInputChange = (e) => {
        const name = e.target.value
        if(e.key === 'Enter') {
            return fetchAndSelect(name)
        }
        setSearchedText(name)
    }


   return (
    <div>
        <h1>Pokemon Search</h1>
        <input type="text" value={searchedText} onKeyUp={(e) => handleInputChange(e)} style={{width:'100%'}} />
        <hr />
        <div>
            {selected ? <PokemonProfile selected={selected} /> : suggestions.map(({name}) => (
                <ShowSuggestion name={name} searchedText={searchedText} setSelected={setSelected}/>
            ))}
        </div>
    </div>
    )
}

But this gives Invalid hook call error.但这会导致Invalid hook调用错误。 If I don't make the query inside useEffect ( I am not sure what is wrong with this?) this time I get Rendered more hooks than during the previous render.如果我不在 useEffect 中进行查询(我不确定这有什么问题?),这次我得到的Rendered more hooks than during the previous render. error.错误。 I am not sure what I am doing wrong?我不确定我做错了什么?

EDIT编辑

Based on answer I edit the code like following根据答案,我编辑代码如下

const Search = () => {
    const [searchedText, setSearchedText] = React.useState(null)
    const [suggestions, setSuggestions] = React.useState([])
    const [selected, setSelected] = React.useState(null)
    const debouncedSearch = debounce(searchedText, 1000) // Trying to debounce the searched text
    const [searchPokemons, { data }] = useLazyQuery(SEARCH);
    const [getPokemon, { pokemon }] = useLazyQuery(GET_POKEMON)

    React.useEffect(() => {
        if (!searchedText) return

        setSelected(null)
        searchPokemons({ variables: { str: searchedText }})

        if (data) {
            console.log(data)
            setSuggestions(data)
        }

    }, [debouncedSearch])


    const fetchAndSelect = name => {
        setSearchedText('')
        getPokemon({variables: {str: name}})
        if (pokemon) {
            setSelected(pokemon)
        }
    }

    const handleInputChange = (e) => {
        const name = e.target.value
        if(e.key === 'Enter') {
            return fetchAndSelect(name)
        }
        setSearchedText(name)
    }

   return (
    <div>
        <h1>Pokemon Search</h1>
        <input type="text" value={searchedText} onKeyUp={(e) => handleInputChange(e)} style={{width:'100%'}} />
        <hr />
        <div>
            {selected ? <PokemonProfile selected={selected} /> : suggestions.map(({name}) => (
                <ShowSuggestion name={name} searchedText={searchedText} setSelected={setSelected}/>
            ))}
        </div>
    </div>
    )
}

I am unable to type anything on the input.我无法在输入中输入任何内容。 It is fetching like crazy.它正在疯狂地获取。 Please help请帮忙

You should use useLazyQuery Hook in this case.在这种情况下,您应该使用useLazyQuery Hook。 It is very useful for things that happen at an unknown point in time, such as in response to a user's search operation.它对于发生在未知时间点的事情非常有用,例如响应用户的搜索操作。

How about If you call use your hook on the top of your function and just call it inside the useEffect hook.如果你在函数顶部调用 use 你的钩子,然后在 useEffect 钩子内调用它,怎么样。

const [search, { data }] = useLazyQuery(SEARCH, {
        variables: {  "str": searchedText },
        pollInterval: 500,
    });

React.useEffect(() => {
        if (searchedText) 
            search() // Function for executing the query

        if (data) 
            setSuggestions(data)

    }, [searchedText])

As you see, useLazyQuery handles fetching data in a synchronous way without any promises.如您所见, useLazyQuery 以同步方式处理获取数据,无需任何承诺。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM