Skip to main content

part e part of | Library | Dart | Flutter

  • part e part of | Library | Dart | Flutter

info

No Dart, uma library é a unidade de organização, encapsulamento e privacidade do código. Oficialmente, cada arquivo Dart — junto com seus parts, se existirem — forma uma library. Identificadores que começam com _ ficam visíveis somente dentro dessa library.

No Dart, part e part of servem para dividir uma mesma library em múltiplos arquivos. Eles não funcionam como import e também não equivalem a partial class do C#. O objetivo é separar um arquivo grande em pedaços menores, mantendo tudo dentro da mesma unidade lógica de library.

Conceito principal

Quando você usa part, os arquivos envolvidos passam a fazer parte da mesma library. Com isso, membros com _ continuam acessíveis entre esses arquivos, porque em Dart o _ indica privacidade no nível de library, não no nível de arquivo.

Como funciona

Você tem um arquivo principal:

library user_page;

import 'package:flutter/material.dart';

part 'user_page_view.dart';
part 'user_page_logic.dart';

class UserPage extends StatefulWidget {
const UserPage({super.key});


State<UserPage> createState() => _UserPageState();
}

class _UserPageState extends State<UserPage> {
int _counter = 0;

void _increment() {
setState(() => _counter++);
}


Widget build(BuildContext context) {
return buildScaffold();
}
}

E os arquivos complementares:

part of 'user_page.dart';

extension _UserPageView on _UserPageState {
Widget buildScaffold() {
return Scaffold(
appBar: AppBar(title: const Text('Usuário')),
body: Center(
child: Text('$_counter'),
),
floatingActionButton: FloatingActionButton(
onPressed: _increment,
child: const Icon(Icons.add),
),
);
}
}
part of 'user_page.dart';

extension _UserPageLogic on _UserPageState {
void carregarDados() {
_counter = 10;
}
}

O que cada palavra-chave faz

part

Declara, no arquivo principal, que outro arquivo pertence à mesma library.

Exemplo:

part 'user_page_view.dart';
part 'user_page_logic.dart';

Isso diz ao compilador que esses arquivos não são libraries independentes; eles são fragmentos da library principal.

part of

Declara, no arquivo secundário, a qual library ele pertence.

Exemplo:

part of 'user_page.dart';

Esse arquivo não deve ser tratado isoladamente. Ele existe como parte da library definida no arquivo principal.

Regras importantes

1. Arquivo com part of não usa import para acessar o principal

Ele não importa o arquivo principal. Ele pertence à mesma library, então o acesso ocorre por compartilhamento da library, não por importação.

2. O import fica no arquivo principal

Na prática, normalmente você centraliza import, export e definição da library no arquivo principal, e os arquivos part ficam só com o código complementar. Isso segue a forma como Dart organiza libraries.

3. Privado com _ continua funcionando entre os arquivos

Como a privacidade é por library, isto funciona:

class _UserPageState extends State<UserPage> {
int _counter = 0;
}

E em outro arquivo part:

part of 'user_page.dart';

extension _UserPageLogic on _UserPageState {
void testar() {
_counter++;
}
}

Isso é permitido porque ambos pertencem à mesma library.

4. part não substitui arquitetura

part ajuda a organizar arquivo grande, mas não separa responsabilidade de verdade. Se a tela está grande porque mistura UI, regra de negócio, acesso a dados e estado, o ideal costuma ser extrair widgets, controllers, services, cubits, blocs ou notifiers. Isso é consistente com a forma como Dart recomenda estruturar bibliotecas e APIs de forma mantível. (Dart)

Quando usar

part faz sentido quando:

  • a tela ficou grande demais;
  • você quer dividir UI, ações e helpers sem perder acesso aos membros privados;
  • tudo ainda pertence claramente à mesma unidade de código.

Exemplo comum em Flutter:

  • produto_page.dart
  • produto_page_view.dart
  • produto_page_actions.dart
  • produto_page_state.dart

Quando evitar

Evite part quando:

  • o código já representa responsabilidades diferentes;
  • você quer reutilizar aquele trecho em outras telas;
  • você quer isolamento mais claro entre camadas;
  • o arquivo secundário deveria ser uma library própria.

Nesses casos, prefira arquivos separados com import, ou componentes específicos da arquitetura da app.

Diferença entre part e import

import

Usado para consumir outra library.

import 'package:flutter/material.dart';

Aqui você está usando código externo à sua library.

part

Usado para incluir outro arquivo na mesma library.

part 'user_page_view.dart';

Aqui você está apenas quebrando a implementação da mesma library em vários arquivos.

Diferença entre part e export

export

Serve para reexpor outra library como parte da API pública.

export 'src/meu_widget.dart';

Isso é útil para organizar API pública de pacote ou módulo. (Dart)

part

Não reexpõe nada. Só divide internamente a mesma library.

Exemplo prático para Flutter

Arquivo principal

library login_page;

import 'package:flutter/material.dart';

part 'login_page_view.dart';
part 'login_page_form.dart';

class LoginPage extends StatefulWidget {
const LoginPage({super.key});


State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();

bool _loading = false;

void _submit() {
setState(() => _loading = true);
}


Widget build(BuildContext context) {
return buildView(context);
}
}

Parte da view

part of 'login_page.dart';

extension _LoginPageView on _LoginPageState {
Widget buildView(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16),
child: buildForm(),
),
);
}
}

Parte do formulário

part of 'login_page.dart';

extension _LoginPageForm on _LoginPageState {
Widget buildForm() {
return Column(
children: [
TextField(controller: _emailController),
TextField(controller: _passwordController),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _loading ? null : _submit,
child: const Text('Entrar'),
),
],
);
}
}

Vantagens

  • reduz o tamanho visual do arquivo principal;
  • mantém acesso a membros privados;
  • facilita separar blocos grandes de UI;
  • útil para telas StatefulWidget muito extensas.

Desvantagens

  • pode esconder acoplamento excessivo;
  • dificulta navegação se usado em excesso;
  • arquivos part não são independentes;
  • não favorece reutilização como libraries separadas.

Boas práticas

Use part para organização local

Bom para separar:

  • builders de UI;
  • extensões internas;
  • helpers específicos da tela;
  • trechos grandes de implementação.

Não use part para tudo

Se um arquivo pode viver sozinho, provavelmente ele deveria ser uma library própria com import.

Prefira nomes claros

Exemplos:

  • pedido_page.dart
  • pedido_page_view.dart
  • pedido_page_actions.dart
  • pedido_page_helpers.dart

Evite espalhar demais

Se uma tela tem 8 ou 10 arquivos part, normalmente já passou do ponto. Nesse caso, a classe provavelmente precisa ser redesenhada.

Erros comuns

Esquecer o part no arquivo principal

part 'user_page_view.dart';

Sem isso, o arquivo secundário não será incluído na library.

Esquecer o part of no arquivo secundário

part of 'user_page.dart';

Sem isso, o arquivo não pertence à library principal.

Tentar usar part como se fosse import

part não serve para compartilhar código entre módulos independentes. Para isso, use libraries separadas com import e, quando fizer sentido, export.

Resumo direto

  • part divide uma mesma library em vários arquivos.
  • part of conecta o arquivo secundário à library principal.
  • _ em Dart é privado por library.
  • part ajuda na organização.
  • part não substitui separação arquitetural.

Regra prática para o seu caso

Se sua tela está grande, você pode usar part para separar:

  • layout;
  • ações;
  • helpers;
  • trechos de estado.

Mas, se ela está grande porque concentra responsabilidades demais, o melhor caminho é extrair widgets e lógica para classes próprias.