# Custom Hooks
- Tempo de leitura estimado: 9 minutos.
### O que são `hooks`?
* Hooks são uma adição ao React (a partir da versão 16.8) onde se permite fazer uso do `state` e outras `features` do React sem a criação de `classes`. Mais informações na documentação do React.
* Regras imprescindíveis para o uso de hooks:
- *Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.*
- *Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions. (There is just one other valid place to call Hooks — your own custom Hooks. We’ll learn about them in a moment.)*
* Exemplos de Custom Hooks:
1. [useIsMobile](https://codesandbox.io/s/useismobile-k8p9t)
Esse custom hook aqui pode ser implementado de algumas formas. A conclusão que cheguei é fazer uso tanto da `innerWidth` da window quanto o `userAgent` do navegador, que em conjunto com alguma biblioteca de detecção de dispositivos, nos diga com exatidão onde estamos atuando em termos de responsividade. No exemplo abaixo o hook customizado recebe por parâmetro (análogo ao `constructor` de classe) duas propriedades, uma a largura da janela para ser testada e a segunda o `userAgent`.
obs.: Com os parâmetros desta forma, se torna possível a utilização em sistemas SSR.
```js
const isMobile = useIsMobile({
width: 768,
customAgent: global.navigator.userAgent
});
```
A largura é diretamente testada contra a `window.innerWidth` e o `userAgent` para este caso, é testado com a biblioteca [ismobilejs](https://github.com/kaimallea/isMobile). O teste pode ser feito manualmente com `RegEx`, por exemplo, sem a necessidade de terceiros.
O uso deste custom hook pode ser feito por demanda, isto é, por página/componente ou pode ser conectado no topo do seu App realizando um disparo à `store` para que todo o sistema fique consciente da mobilidade.
- exemplo conectado à `store`: (obs, qualquer uso de estado causa um re-render, o que talvez não seja interessante para todo o App).
```js
export const App = () => {
const isMobile = useIsMobile({
width: 768,
customAgent: global.navigator.userAgent
});
const dispatch = useDispatch();
dispatch(setIsMobile(isMobile));
}
```
- exemplo utilizado por demanda:
```js
function App() {
const isMobile = useIsMobile({
width: 768,
customAgent: global.navigator.userAgent
});
return (
<div className="App">
<h1>{isMobile ? "This is on mobile" : "This is on desktop"}</h1>
</div>
);
}
```
Este custom hook faz uso de:
1. useState
2. useEffect
2. [useModalWrapper](https://codesandbox.io/s/usemodal-as-a-wrapper-uit30)
Este custom hook faz uso da habilidade de [`Portals`](https://reactjs.org/docs/portals.html) do React onde se é possível montar um componente em qualquer outro lugar do DOM independente de contexto. Novamente, em analogia a um construtor, como parâmetro `bindToElement` é passado o nó desejado para a renderização.
Este custom hook nos retorna as seguintes propriedades:
1. ModalWrapper, que nada mais nada menos é, um HOC.
2. isOpen, como o nome mesmo já diz, nos informa se a modal está aberta ou não.
3. openModal, atuando diretamente como controle para a abertura da modal.
4. closeModal, assim como a openModal porém para seu fechamento.
Sua aplicação é bem direta, monte o Wrapper dentro de seu componente e coloque a modal desejada (isso pode variar de aplicação para aplicação e consequentemente sua estilização CSS também no quesito de posicionamento).
O Wrapper recebe por `props` duas coisas: o `backdrop` e o `fade`, sendo o segundo apenas possível com o primeiro.
O primeiro disponibiliza a habilidade de clicar fora da modal para seu fechamento (ou apertar ESC ou qualquer outra condicional) e o segundo cria uma janela translúcida por trás (puramente estilo).
```js
const {ModalWrapper, isOpen, openModal, closeModal} = useModalWrapper({
bindToElement: global.document.getElementById('modal-root')
});
{
isOpen && (
<ModalWrapper backdrop={true} fade={true}>
<MyBeautifulModal closeModal={closeModal} />
</ModalWrapper>
);
}
<button type="button" onClick={() => openModal()}>
Click to Open
</button>
```
Este custom hook faz uso de:
1. useState
2. useEffect
3. useRef
4. React e ReactDOM
3. [useIsLoading](https://codesandbox.io/s/useisloading-connected-9s8gt)
Observação: idealmente utilizado com aplicações com gerenciamento de estado global como por exemplo o `redux`.
Este custom hook eu diria até que chega a ser perfumaria no entanto achei interessante por duas razões, abstração de código assim como todos os demais hooks nos oferecem e independência do acesso à `store`. Fica bem simplificado seu uso.
O componente que necessitar do Loading a partir de alguma ação assíncrona não precisará acessar a `store` de forma alguma.
```js
const [isLoading, Loading] = useIsLoading();
if (isLoading) return <Loading />;
return <MyComponentAfterLoading />;
```
Este custom hook faz uso de:
1. React
2. useSelector (react-redux)
3. Componente de Loading
4. useAuth
Este custom hook pode ser implementado de diversas formas e isso pode variiar de acordo com a necessidade e implementação de cada projeto, no entanto a sua ideia é basicamente a mesma, prover mecanismos de autenticação para páginas.
O custom hook useAuth pode retornar os métodos e propriedades abaixo diretamente ou pode-se dividir suas responsabilidades, conforme abaixo.
```js
const {isLogged, doLogin, authInfo} = useLogin();
const {doLogout} = useLogout();
```
As propriedades acima descritas abaixo:
1. isLogged, retorna verdadeiro ou falso para a condicional de autenticado ou não no sistema.
2. doLogin, dispara a ação para realizar a autenticação.
3. authInfo, retorna objeto com informações pertinentes à autenticação.
4. doLogout, dispara a ação pertinente para deslogar do sistema.
Este custom hook faz uso de:
1. useEffect
2. useSelector e useDispatch (react-redux)
3. useHistory, useLocation (react-router-dom)
5. [useInput](http://codesandbox.io/s/useinput-v66nu)
Este custom hook é também bem simples no entanto um tanto quanto útil quando se é preciso lidar com `inputs` de formulário.
Bem direto, o custom hook retorna os valores dos inputs e o `handler` de `onChange`. A mágica do controle de estado está toda por dentro do `useInput`.
```
const [values, handleChange] = useInput();
function handleSubmit(e) {
e.preventDefault();
console.log("values", values);
}
<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
placeHolder="Name"
onChange={handleChange}
/>
</form>
```
Este custom hook faz uso de:
1. useState
Demais possibilidades:
https://usehooks.com/