Try   HackMD

DAOhaus v3 UI & Connect Tutorial

Our libraries work with client side rendered React apps.

  • may branch to Next.js
  • We recommend people use Vite
    • Vite has some quirks when you bring in other libraries

Create a new Vite app:

  • npm create vite@latest
  • Choose project name
  • Choose package name
  • Select "React"
  • Select "Typescript"
  • cd project_name
  • npm install
  • npm run dev

Vite has a problem with libraries that use Globals. Our libraries use Globals.

  • Create a new script tag in index.html
  • add <script> window.global = window</script>

Vite doesn't have access to process.env - so if you bring in a library that's looking for a process env variable - Vite wants you to import everything through import.meta

  • Edit vite.config.ts
  • add the define section, should look like this:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  define:{
    'process.env': {
      NODE_ENV: import.meta['VITE_NODE_ENV'],
    }
  },
  plugins: [react()]
})

Hello World

Let's simplify App.tsx in preparation for the DAOhaus libraries. Replace the contents of App.tsx with the following.


function App() {
    return (
        <div className="App">
            Hello World
        </div>
    )
}

export default App

And delete import './index.css' from main.tsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
)

Load the page and you should see an unstyled "Hello World" in the top left corner.

Style the app with the DAOhaus Theme Provider

The DAOhaus UI package provides a theme and various UI components to help you quickly build your new DAO app. This UI library is best when building a new app and shouldn't be used within existing apps (TODO: Because why?)

Install the UI library with this command:

yarn add @daohaus/ui

Open main.tsx and add to the top:
import {HausThemeProvider} from '@daohaus/ui';

and wrap your <App /> tag with <HausThemeProvider>

main.tsx should look like this:

import {HausThemeProvider} from '@daohaus/ui';
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <HausThemeProvider>
      <App />
    </HausThemeProvider>
  </React.StrictMode>
)

Refresh the app and you will see the app is now in dark mode, with the default text styling.

HausThemeProvider has parameters.
TODO: How do I get all of the parameters for HausThemeProvider?

  • startDark={false} //HausThemeProvider defaults to Dark Mode
  • defaultDark={ThemeObject} //TODO: What are theme objects?
  • defaultLight={ThemeObject}

Adding a layout

Return to App.tsx and wrap your "Hello World" in a <MainLayout> and <H1>
tag.

import {H1, MainLayout} from "@daohaus/ui";

function App() {

  return (
    <MainLayout>
      <H1>
        Hello World
      </H1>
    </MainLayout>
  )
}

export default App

TODO: Are there other layouts? How are they configured, where are the layout docs?

Included Imports

This library includes many React dependencies under the hood. This includes React Router and React Hook Form.

Because of this, we can easily install HashRouter (which will later help us deploy onto an IPFS based deployment).

add import {HashRouter} from 'react-router-dom'; to main.tsx

Look in your node_modules folder and note that react-router-dom is already included in the app as a consequence of installing @daohaus/ui The same is true of react-hook-form

If you don't end up using these in your app, it will be optimized out when you deploy your app.

Add Form Elements

Let's add a "WrappedInput" tag to get some input from the user. WrappedInput comes from the @daohaus/ui library, but it requires the FormProvider context from 'react-hook-form', which requires useForm.

Modify your App.tsx to match the following:

import {H1, MainLayout, WrappedInput} from "@daohaus/ui";
import {useForm, FormProvider} from 'react-hook-form';

function App() {
  const methods = useForm();
  
  return (
    <FormProvider {...methods}>
      <MainLayout>
        <H1>
          Hello World
        </H1>
        <WrappedInput id="test" />
      </MainLayout>
    </FormProvider>
  )
}

export default App

DAOhaus Connect

import the DAOhaus connect library
yarn add @daohaus/connect

This will connect you to an RPC, allowing you to use things like MetaMask. It will also pull down your DAOhaus profile, handling your ENS fetches, eventually your LENS protocol fetch and bringing that into the application relatively easily.


import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import {HashRouter} from 'react-router-dom';
import {HausThemeProvider} from '@daohaus/ui';
import {DHConnectProvider} from '@daohaus/connect'

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <HashRouter>
      <HausThemeProvider>
        <DHConnectProvider>
          <App />
        </DHConnectProvider>
      </HausThemeProvider>
    </HashRouter>
  </React.StrictMode>
)

Every time we layer a context into the base level, these contexts share data to the rest of your application. This means we can go into App.tsx and import elements.

Lets try this by importing the DAOhaus Nav bar.

Add <DaoHausNav /> inside of <FormProvider tag in App.tsx

        ...
return (
    <FormProvider {...methods}>
      <DaoHausNav />
      <MainLayout>
        ...

This will automatically add authentication functionality to your app.

Let's go one step further. Instead of adding DaoHausNav manually, let's bring DHLayout. This will give us DAOHausNav and menu functionality together.

Change your import:
import {DHLayout} from '@daohaus/connect'

Wrap your <MainLayout /> tag with <DHLayout>

function App() {
  const methods = useForm();
  const {pathname} = useLocation();

  return (
    <FormProvider {...methods}>
        <DHLayout pathname={pathname} navLinks={[
          {href: "/", label: "Home"},
          {href: "/dao", label: "DAO"}
        ]}>
          <MainLayout>
            <H1>
              Hello World
            </H1>
            <WrappedInput id="test" />
          </MainLayout>
      </DHLayout> 
    </FormProvider>
  )
}