首页 > 解决方案 > 添加渲染表单时出现错误“无效的钩子调用”

问题描述

我试图在两个单选按钮上使用状态,当您选择每个按钮时呈现不同的表单,但是当我尝试添加地图以咨询地址时,会出现此无效的挂钩调用,我不知道如何解决此问题。这是代码

    const Pointer = () => (
      <img id="pointer" alt="ícone localização" src={pinterIcon} alt="Pointer" />
    )

    const [mask, setMask] = useState('999.999.999-999')
    const [maskPhone, setMaskPhone] = useState('(99) 9999-99999')

    const [phone, updatePhone] = useState('')
    const [address, updateAddress] = useState('')
    const [coordinates, updateCoordinates] = useState([0, 0])

    const GOOGLE_MAPS_API_URL =
    'https://maps.googleapis.com/maps/api/geocode/json'

    function getAddressByCoordinates(latitude, longitude) {
    axios
      .get(
        `${GOOGLE_MAPS_API_URL}?address=${latitude}+${longitude}&key=${process.env.GATSBY_GOOGLE_MAPS_API_KEY}`
      )
      .then(response => {
        const { results } = response.data  
        if (results.length === 0) return

        updateAddress(results[0].formatted_address)
      })
    }

    useEffect(() => {
      navigator.geolocation.getCurrentPosition(position => {
        const { latitude, longitude } = position.coords

        updateCoordinates([latitude, longitude])

        getAddressByCoordinates(latitude, longitude)
      })
    }, [])

    async function handleSubmit(event) {
      event.preventDefault()

      const response = await api.post('clients', {
        
        address,
        latitude: coordinates[0],
        longitude: coordinates[1],
      })
    }

    async function handleMapClick(event) {
      updateCoordinates([event.lat, event.lng])

      getAddressByCoordinates(event.lat, event.lng)
    }

    function handleGetCoordinates() {
      if (address.length > 0) {
        axios
          .get(
            `${GOOGLE_MAPS_API_URL}?address=${address}&key=${process.env.GATSBY_GOOGLE_MAPS_API_KEY}`
          )
          .then(response => {
            const { results } = response.data

            if (results.length === 0) return

            updateAddress(results[0].formatted_address)
            updateCoordinates([
              results[0].geometry.location.lat,
              results[0].geometry.location.lng,
            ])
          })
      }
    }

    const handleValidadePhone = event => {
      const { value } = event.target
      if (value.length > 14) {
        setMaskPhone('(99) 99999-9999')
      } else {
        setMaskPhone('(99) 9999-99999')
      }
      updatePhone(value)
    }

    const handleChangePhone = event => {
      updatePhone(event.target.value)

      handleValidadePhone(event)
    }

    class App extends Component {
      
      constructor(props) {
        super(props);
        this.state = {
          internet: ""
        };
      }

      handleChange = (e) => this.setState({ [e.target.name]: e.target.value });

      renderForm = () => {
        switch (this.state.internet) {
          case "residencial":
            return (
                    <form className="form" autoComplete="off">
                        <div className="input-block">
                          <label htmlFor="name">Nome</label>
                          <input
                            type="text"
                            name="name"
                            id="name"
                            onChange={props.handleChange}
                            required
                          />
                        </div>
                        <div className="input-block">
                            <label htmlFor="email">Email</label>
                            <input
                              type="email"
                              name="email"
                              id="email"
                              onChange={props.handleChange}
                              equired
                            />
                        </div>

                        <div className="input-block">
                            <label htmlFor="phone">Telefone</label>
                            <input
                              mask={maskPhone}
                              maskChar=""
                              type="phone"
                              name="phone"
                              id="phone"
                              onChange={handleChangePhone}
                              required
                            />
                        </div>
                        <div className="input-block" id="input">
                            <label 
                            htmlFor="address"
                            >
                              Endereço
                            </label>
                            <input
                              type="text"
                              id="address"
                              value={address}
                              onChange={event => updateAddress(event.target.value)}
                              onBlur={handleGetCoordinates}
                              placeholder="Rua, Número, Bairro, Cidade, UF"
                              required
                            />
                        </div>

                        <div className="btn-address">
                            <button 
                              type="submit"
                              className="address-btn"
                              >Consultar Endereço
                            </button>
                        </div>

                        <div style={{ height: '430px', width: '100%', marginTop: '20px' }}>
                            <GoogleMap
                              bootstrapURLKeys={{
                                key: 'AIzaSyDRDXI4V6LTjYIZ6rdi5j9soHPCVv_NIl0',
                              }}
                              zoom={15}
                              center={coordinates}
                              onClick={handleMapClick}
                            >
                              <Pointer lat={coordinates[0]} lng={coordinates[1]} />
                            </GoogleMap>
                        </div>
                      </div>
                    </form>
            );
          case "empresarial":
            return (

                    <form className="form">
                      <div>
                        This one works
                      </div>
                    </form>
            );
          default:
            return null;
        }
      };

      render() {
        return (
          <Container>
            <section className="sectio">
              <div className="check-blok" onChange={this.onChangeValue}>
                <div className="check">
                  <input
                    type="radio"
                    id="residencia"
                    name="internet"
                    value="residencial"
                    onChange={this.handleChange}
                  />
                  <label for="residencial">Internet Residencial</label>
                  <input
                    type="radio"
                    id="empresa"
                    name="internet"
                    value="empresarial"
                    onChange={this.handleChange}
                  />
                  <label for="empresarial">Internet Empresarial</label>
                </div>
              </div>
              <div className="emp-sec">
                {this.renderForm()}
              </div>
              <div className="continue">
                <button
                  className="btn-continue"
                  onClick={this.handleContinue}
                  // onClick={props.next}
                >
                  Continuar
                </button>
              </div>
            </section>
          </Container>
        )
      }
    }
    export default App ;

当我从代码中删除地图及其功能时,它可以工作,但我需要它。也改变了功能,但仍然没有奏效。

标签: javascriptreactjsreact-hooks

解决方案


我想主要问题是你在函数useEffect内部使用钩子getAddressByCoordinates。挂钩调用应该发生在组件的根级别。您需要从该功能移出到根级别。

从技术上讲,您违反了Hooks 规则仅在顶层调用 Hooks

不要在循环、条件或嵌套函数中调用 Hook。相反,请始终在 React 函数的顶层使用 Hooks。通过遵循此规则,您可以确保每次渲染组件时都以相同的顺序调用 Hook。这就是允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 状态的原因。


推荐阅读