Estado e cidade
Escolha um estado e as cidades dele carregam sob demanda, com Brazilian Utils em React, Angular, Vue e JavaScript puro.
Um guia da biblioteca JavaScript. Arquivo original
Funções usadas: Municípios: Listar, Estados (UF): Listar
Escolha um estado e as cidades dele preenchem o segundo select. Escolha o framework: cada exemplo roda o código logo abaixo dele, que pode ser copiado do jeito que está.
O ponto aqui é quando cada tabela é carregada, e a resposta é: quando alguém abre o select que a mostra. Nem com a página, nem ao escolher um estado. Num formulário em que a cidade vem preenchida de outro lugar, ou é deixada em branco, os 76 KB de municípios nunca são buscados. Os estados são 27 linhas, 2,2 KB; os municípios são 5.571, 76 KB. Cada utilitário é um subpath, então await import("@brazilian-utils/brazilian-utils/get-municipalities") busca essa tabela e nada mais. Cada opção usa o code IBGE do município como valor e o name como rótulo, já que os nomes se repetem entre estados (existem dois "Pau D'Arco"). O bundler transforma isso num chunk separado, e o browser busca uma vez e guarda, então só a primeira abertura espera.
Um hook por lista, cada um buscando sua tabela quando o onFocus avisa que o select foi aberto. As cidades são de um estado, então o que foi carregado só vale como as cidades da tela enquanto aquele estado for o escolhido:
Carregando o exemplo…
import { useId, useState } from "react";
import { useCitiesOfState } from "./use-cities-of-state";
import { useStates } from "./use-states";
export function StateCity() {
const id = useId();
const [state, setState] = useState("");
const { states, loading: loadingStates, load: loadStates } = useStates();
const { cities, loading: loadingCities, load: loadCities } = useCitiesOfState(state);
return (
<>
<label htmlFor={id}>State</label>
{/* Opening the select is what says the list is wanted, so that is when it is fetched. */}
<select
id={id}
value={state}
aria-busy={loadingStates}
onFocus={loadStates}
onChange={(event) => setState(event.currentTarget.value)}
>
<option value="">{loadingStates ? "Loading the states…" : "Pick a state"}</option>
{states.map((current) => (
<option key={current.code} value={current.code}>
{current.name}
</option>
))}
</select>
<label htmlFor={`${id}-city`}>City</label>
<select id={`${id}-city`} disabled={!state} aria-busy={loadingCities} onFocus={loadCities}>
<option value="">{loadingCities ? "Loading the cities…" : "Pick a city"}</option>
{cities.map((city) => (
<option key={city.code} value={city.code}>
{city.name}
</option>
))}
</select>
</>
);
}Um resource sem nada para perguntar espera, que é onde os dois começam; abrir o select dá a ele o que perguntar. As cidades são do estado para o qual foram pedidas, então escolher outro estado devolve esse resource à espera:
Carregando o exemplo…
Carregando o código…
Um composable por lista, cada um buscando sua tabela quando o @focus avisa que o select foi aberto. As cidades são de um estado, então o que foi carregado só vale como as cidades da tela enquanto aquele estado for o escolhido:
Carregando o exemplo…
Carregando o código…
Sem build: salve como um arquivo .html e abra. Cada subpath é um módulo próprio no CDN, e o import() dentro de um listener de focus busca esse módulo na primeira vez que o select é aberto.
Carregando o exemplo…
Carregando o código…
A introdução lista todos os utilitários que embutem uma tabela e valem um subpath próprio.
