Skip to content

Página (Screen) ​

A Página ou Screen é o componente de mais alto nível na nossa hierarquia de visualização. Ela é responsável por orquestrar a interface, capturar as intenções do usuário e exibir os dados processados pelas camadas inferiores.


1. Estrutura e Responsabilidade ​

Uma tela deve ser composta por dois arquivos principais:

  1. *.screen.tsx: Contém apenas a estrutura visual (JSX) e o mapeamento de propriedades.
  2. *-screen.hooks.ts: Contém toda a lógica de estado, chamadas de hooks de feature, handlers e efeitos.

Regra de Ouro da Tela ​

A tela é a única responsável por disparar feedbacks visuais diretos (Toasts, Modais de Alerta, Haptics). Nenhuma outra camada (Feature ou Application) deve fazer isso.


2. Fragmentos de Tela (Fragment Components) ​

Para evitar que um arquivo de tela cresça demais, dividimos a interface em Fragmentos. Veja o guia detalhado sobre Fragment Components.

Regra de Comunicação dos Fragmentos: ​

  • Passagem de Propriedades: Um fragmento sempre deve receber seus dados e ações via props.
  • Isolamento de Estado: Um fragmento nunca deve saber como obter informações da API ou acessar o estado global diretamente. Ele é um componente "burro" que apenas renderiza o que a Tela (Pai) envia.

3. Exemplo Completo: Gerenciamento de Usuários ​

Abaixo, um exemplo de uma tela que utiliza Redux Saga para ações globais e TanStack Query para dados de domínio.

A. O Hook da Tela (users-screen.hooks.ts) ​

typescript
export function useUsersScreen() {
    // 1. Dados de Domínio (TanStack Query)
    const { data: users, isLoading, refetch } = useGetUsers();
    
    // 2. Estado Local da Tela
    const [searchTerm, setSearchTerm] = useState("");

    // 3. Ação Global (Redux)
    const dispatch = useDispatch();

    const handleLogout = () => {
        // Usamos Redux Saga para processos de infraestrutura/globais (como limpar sessão)
        dispatch(logoutAction());
    };

    const handleUpdateStatus = (id: string, active: boolean) => {
        // As actions são da camada de aplicação e apenas realizam a chamada
        updateUserStatusAction(id, active).then(() => {
            refetch(); // Atualiza a lista via TanStack (Camada Feature)
            Toast.show("Usuário atualizado com sucesso!"); // Feedback visual (Camada Screen)
        }).catch((error) => {
            // O tratamento de erro ocorre aqui na Screen
            Toast.show("Falha ao atualizar usuário");
        });
    };

    return {
        users: users?.filter(u => u.name.includes(searchTerm)) ?? [],
        isLoading,
        searchTerm,
        setSearchTerm,
        handleLogout,
        handleUpdateStatus
    };
}

B. O Componente da Tela (users.screen.tsx) ​

tsx
import { useUsersScreen } from "./users-screen.hooks";
import { UserListFragment } from "./fragments/user-list-fragment";

function UsersScreen() {
    const { 
        users, 
        isLoading, 
        handleUpdateStatus, 
        handleLogout 
    } = useUsersScreen();

    return (
        <ScreenContainer>
            <Header title="Gestão de Usuários" onLogout={handleLogout} />
            
            {isLoading ? (
                <LoadingState />
            ) : (
                /* Passamos as propriedades para o Fragmento. 
                   O fragmento não sabe de onde vem os 'users' */
                <UserListFragment 
                    data={users} 
                    onAction={handleUpdateStatus} 
                />
            )}
        </ScreenContainer>
    );
}

C. O Fragmento (fragments/user-list-fragment.tsx) ​

tsx
interface UserListFragmentProps {
    data: User[];
    onAction: (id: string, active: boolean) => void;
}

// O Fragmento recebe TUDO via props.
function UserListFragment({ data, onAction }: UserListFragmentProps) {
    return (
        <List>
            {data.map(user => (
                <UserCard 
                    key={user.id}
                    name={user.name}
                    isActive={user.active}
                    onToggle={() => onAction(user.id, !user.active)}
                />
            ))}
        </List>
    );
}

4. Por que usar cada tecnologia? ​

Por que Redux Saga? ​

  • Finalidade: Gerenciar Side-Effects Globais e Infraestrutura.
  • Quando usar: Fluxos de autenticação, sincronização de persistência (Storage), logs de auditoria e estados que precisam persistir durante toda a sessão do app (ex: perfil do usuário logado).
  • Vantagem: Controle total sobre fluxos assíncronos complexos e sequenciais.

Por que TanStack Query? ​

  • Finalidade: Gerenciar Server State (Dados da API).
  • Quando usar: Listagens, detalhes de registros, caches de busca e qualquer dado que venha do banco de dados e precise de sincronização automática.
  • Vantagem: Gerenciamento automático de cache, estados de loading/error prontos e invalidação inteligente de dados (quando um componente altera um dado, todos os outros que usam a mesma "chave" são atualizados automaticamente).

5. Resumo de Boas Práticas ​

  1. Componentes sempre como function: Nunca use const para declarar componentes.
  2. Lógica fora da Screen: Se houver um if ou um map complexo que não seja puramente visual, ele deve estar no hook.
  3. Fragmentos Puros: Nunca deixe um fragmento acessar o useSelector ou useQuery. Peça o dado para o pai.
  4. Propagação de Props: Fragmentos são excelentes para dividir a tela, mas lembre-se de tipar as props corretamente para manter a segurança do código.