Apollo React 为什么无法在 UseEffect hook 内查询

mr_*_*ing 8 javascript apollo reactjs graphql

我刚刚学习 Apollo-React 但无法发出 graphql 请求

这就是我在没有阿波罗的情况下所做的事情

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>
    )
}

Run Code Online (Sandbox Code Playgroud)

现在没有我自己的 sendQuery 函数,我想使用 Apollo 的 useQuery hook。

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

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

Run Code Online (Sandbox Code Playgroud)

这些是我在操场上正确的查询和结果。现在我再次编写搜索功能。我说每当 searchedText 发生变化(当用户输入时),查询搜索并将返回的数据设置为建议。每当用户按下回车键时,我想从后端查询神奇宝贝并将其设置为选定状态。


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>
    )
}

Run Code Online (Sandbox Code Playgroud)

但这会导致Invalid hook调用错误。如果我不在 useEffect 中进行查询(我不确定这有什么问题?),这次我会收到Rendered more hooks than during the previous render.错误。我不确定我做错了什么?

编辑

根据答案我编辑代码如下

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>
    )
}
Run Code Online (Sandbox Code Playgroud)

我无法在输入框中输入任何内容。它太让人疯狂了。请帮忙

bde*_*rka 4

在这种情况下,您应该使用useLazyQuery 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])

Run Code Online (Sandbox Code Playgroud)

如您所见,useLazyQuery 以同步方式处理数据获取,没有任何承诺。

  • 此效果不会捕获“数据”(不同时间,使用“onCompleted”选项)...不需要将数据复制到状态中 (2认同)