Linking and Navigating

Learn how navigation works in Bini.js and how to use the Link component and useNavigate hook.

Bini.js provides built-in navigation components and hooks that enable fast, client-side transitions between routes without full page reloads.

useNavigate Hook

The useNavigate hook returns a function that lets you navigate programmatically. It's auto-imported in all pages and layouts.

app/login/page.tsx
// src/app/login/page.tsx
export default function LoginPage() {
  const navigate = useNavigate()

  const handleSubmit = async (e) => {
    e.preventDefault()
    
    // Perform login logic...
    const success = await loginUser()
    
    if (success) {
      // Navigate to dashboard after successful login
      navigate('/dashboard')
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* form fields */}
      <button type="submit">Login</button>
    </form>
  )
}

Navigate Options

OptionTypeDescription
replacebooleanReplace the current entry in history
stateanyState to persist to the location
// Navigate with options
navigate('/profile', { replace: true, state: { from: 'login' } })

// Go back
navigate(-1)

// Go forward
navigate(1)

useParams Hook

The useParams hook returns an object of key/value pairs of the dynamic route parameters from the current URL.

app/blog/[slug]/page.tsx
// src/app/blog/[slug]/page.tsx
export default function BlogPost() {
  const { slug } = useParams()
  
  return (
    <div>
      <h1>Blog Post: {slug}</h1>
    </div>
  )
}

// URL: /blog/hello-world
// useParams() returns { slug: 'hello-world' }
app/shop/[...slug]/page.tsx
// src/app/shop/[...slug]/page.tsx
export default function ShopCategory() {
  const { slug } = useParams()
  // slug is an array: ['clothing', 'shirts']
  
  return (
    <div>
      <h1>Category: {slug.join(' / ')}</h1>
    </div>
  )
}

useLocation Hook

The useLocation hook returns the current location object. Useful for accessing the current pathname, search params, and state.

app/components/Breadcrumbs.tsx
// src/app/components/Breadcrumbs.tsx
export default function Breadcrumbs() {
  const location = useLocation()
  const pathnames = location.pathname.split('/').filter(x => x)

  return (
    <nav>
      <Link to="/">Home</Link>
      {pathnames.map((name, index) => {
        const routeTo = `/${pathnames.slice(0, index + 1).join('/')}`
        const isLast = index === pathnames.length - 1

        return (
          <span key={name}>
            {' / '}
            {isLast ? (
              <span>{name}</span>
            ) : (
              <Link to={routeTo}>{name}</Link>
            )}
          </span>
        )
      })}
    </nav>
  )
}

useSearchParams Hook

The useSearchParams hook reads and updates the query string. It returns a URLSearchParams object and a setter function.

app/shop/page.tsx
// src/app/shop/page.tsx
export default function ShopPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const category = searchParams.get('category') || 'all'
  const sort = searchParams.get('sort') || 'newest'

  const handleCategoryChange = (newCategory) => {
    setSearchParams({ category: newCategory, sort })
  }

  const handleSortChange = (newSort) => {
    setSearchParams({ category, sort: newSort })
  }

  return (
    <div>
      <h1>Shop</h1>
      <p>Category: {category}</p>
      <p>Sort: {sort}</p>
      
      <button onClick={() => handleCategoryChange('electronics')}>
        Electronics
      </button>
      <button onClick={() => handleCategoryChange('clothing')}>
        Clothing
      </button>
    </div>
  )
}

Programmatic Navigation

Common patterns for programmatic navigation in Bini.js:

After Form Submission

const navigate = useNavigate()

const handleSubmit = async (data) => {
  await saveData(data)
  navigate('/success')
}

Conditional Navigation

const navigate = useNavigate()

useEffect(() => {
  if (!user) {
    navigate('/login')
  }
}, [user])

With State

// Passing state
navigate('/checkout', { state: { cartItems } })

// Receiving state
const location = useLocation()
const { cartItems } = location.state || {}

Best Practices

  • Use <Link> for standard navigation links
  • Use <NavLink> for navigation menus that need active state styling
  • Use useNavigate for programmatic navigation (form submissions, redirects)
  • Use useParams to access dynamic route parameters
  • Use useSearchParams for managing query strings and filters
  • All navigation hooks and components are auto-imported — no need to write import statements