npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@rownd/react

v2.4.0

Published

## Installation

Downloads

698

Readme

React / Next.js

Installation

Simply run npm install @rownd/react or yarn add @rownd/react.

Usage

React

The library provides a React provider and hook for the Rownd browser API.

In your app's main entrypoint, add the Rownd provider, likely before other providers:

import React from 'react',
import ReactDOM from 'react-dom';
import { RowndProvider } from '@rownd/react';
import App from './App';

ReactDOM.render(
  <RowndProvider
    appKey="<your app key>"
  >
    <App />
  </RowndProvider>,
  document.getElementById('root')
);

{% hint style="warning" %} The Rownd React SDK automatically injects the Rownd Hub snippet into your React application, so you should not manually include the Hub snippet in your HTML page. Doing so will produce unexpected results. {% endhint %}

RowndProvider props

  • appKey (required): This is the key generated by the Rownd dashboard.
  • postLoginRedirect (optional): Where the browser should redirect the user after a successful sign-in. If not supplied, the user will remain on the same page.
  • rootOrigin (optional): If you're using Rownd across multiple domains (e.g., rownd.io and app.rownd.io), set this to the "root" origin (e.g., https://rownd.io).

React Next.js

Rownd currently utilizes client-side rendering for some of its components.

In the root layout.tsx of your app:

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode,
}>) {
  return (
    <html lang="en">
      <body>
        <NextJSRowndProvider
          appKey="<your app key>"
          apiUrl="<your api url>"
          hubUrlOverride="<your hub url>"
        >
          {children}
        </NextJSRowndProvider>
      </body>
    </html>
  );
}

NextJSRowndProvider props

  • appKey (required): This is the key generated by the Rownd dashboard.
  • apiUrl (optional): The URL of your Rownd API instance.
  • hubUrlOverride (optional): The URL of your Rownd Hub instance.

Be sure to import the Rownd NextJS component from @rownd/react/next

Later on within your app's components, you can use the Rownd hook to access the Rownd browser API:

"use client";
import React from 'react';
import { useRownd } from '@rownd/react/next';

export default function MyProtectedComponent(props) {
  const { is_authenticated, user, requestSignIn, is_initializing } = useRownd();

  useEffect(() => {
    if (!is_authenticated && !is_initializing) {
      requestSignIn();
    }
  }, [is_authenticated, is_initializing]);

  return (
    <div>
      {is_authenticated ? (
        <div>
          <h1>Welcome {user.data.full_name}</h1>
          <button onClick={() => getAccessToken()}>Get access token</button>
        </div>
      ) : (
        <div>
          <h1>Please sign in to continue</h1>
        </div>
      )}
    </div>
  );
}

Usage with redux, etc

Often, sending and receiving data from your server will rely on the Rownd access token as a means of authenticating the user within your back-end (see our Node.js SDK as an example of this). Many React apps leverage Redux or similar technologies to manage an app's global state.

The key here is to call Rownd's getAccessToken({ waitForToken: true }) method when calling your own authenticated APIs. For example, if you're using axios, you'd likely set up an interceptor that looks something like this:

// api-client.js

import axios from 'axios';

let getAccessToken;

axios.interceptors.request.use(async (config) => {
  if (!getAccessToken) {
    return config;
  }

  if (config.skipAuth || !config.url.startsWith('/api')) {
    return config;
  }

  const accessToken = await getAccessToken({ waitForToken: true });

  config.headers.common.Authorization = `Bearer ${accessToken}`;
  return config;
});

export function setAccessTokenHelper(fn) {
  getAccessToken = fn;
}

export default axios;

Here's another example, this time using ky:

// api-client.js

import ky from 'ky';

let getAccessToken;

ky.extend({
  hooks: {
    beforeRequest: [
      // Auto-refresh tokens
      async (request) => {
        if (!getAccessToken) {
          return;
        }

        if (request.skipAuth || !request.url.startsWith('/api')) {
          return;
        }

        const accessToken = await getAccessToken({ waitForToken: true });

        request.headers.set(
          'Authorization',
          `Bearer ${tokenResp.access_token}`
        );
      },
    ],
  },
});

function setAccessTokenHelper(fn) {
  getAccessToken = fn;
}

export { api, setAccessTokenHelper };

In both of the cases above, our async actions would use these instances of axios or ky to make requests back to the server, but before any of those fire, we need to set the access token helper from our React app like this:

// AppWrapper.jsx

import { useRownd } from '@rownd/react';
import { setAccessTokenHelper } from './api-client';
import App from './app';

export default function MyReactAppWrapper() {
  const { getAccessToken } = useRownd();

  useEffect(() => {
    setAccessTokenHelper(getAccessToken);
  }, [getAccessToken]);

  return <App />;
}

That's one way to solve this problem. Another might be to wrap the redux provider in your own component and simply pass the getAccessToken function down into the store during initialization. If you come up with a better mousetrap here, let us know!

API reference

Most API methods are made available via the Rownd Provider and its associated useRownd React hook. Unless otherwise noted, we're assuming that you're using hooks.

requestSignIn()

Trigger the Rownd sign in dialog

const { requestSignIn } = useRownd();

requestSignIn({
  auto_sign_in: false, // optional
  identifier: '[email protected]' || '+19105551212', // optional
});
  • auto_sign_in: boolean - when true, automatically trigger a sign-in attempt if identifier is included or an email address or phone number has already been set in the user data.
  • identifier: string - an email address or phone number (in E164 format) to which a verification message may be sent. If the Rownd app is configured to allow unverified users, then sign-in will complete without verification if the user has not signed in previously.

signOut()

Sign out the user and clear their profile, returning them to a completely unauthenticated state.

const { signOut } = useRownd();
signOut();

getAccessToken()

Retrieves the active, valid access token for the current user.

const { getAccessToken } = useRownd();

let accessToken = await getAccessToken({
  waitForToken: false,
});
  • waitForToken: boolean - when true, if no access token is present or if it's expired, the promise will not resolve until a valid token is available. While unlikely, this could result in waiting forever.

is_initializing

is_initializing will be true until the Hub has fully loaded, recalled its state, and resolved the current user's authentication status. This usually takes only a few milliseconds, but if you make decisions that depend on the is_authenticated flag while is_initializing is still true, your code/logic may not work as you expect.

const { is_initializing } = useRownd();

if (is_initializing) {
  // return loading state or null
}

is_authenticated

Indicates whether the current user is signed in or not.

const { is_authenticated } = useRownd();

return (
  <>
    {is_authenticated && <ProtectedRoute />}
    {!is_authenticated && <PublicRoute />}
  </>
);

access_token

Represents the current access token for the user.

const { access_token } = useRownd();

useEffect(() => {
    axios({
        method: 'post',
        url: '/api/sessions'
        headers: {
            authorization: `Bearer ${access_token}`
        }
    }).then(console.log);
}, [access_token]);

user

Represents information about the current user, specifically their profile information. In the example below, we use the existing data to display the current value of first_name in a form field, update a local copy of that data as the user changes it, and then save the changes to Rownd once the user submits the form.

const { user } = useRownd();

const [profile, setProfile] = useState(user.data);

return (
  <form onSubmit={() => user.set(profile)}>
    <label htmlFor="first_name">
      <input
        id="first_name"
        type="text"
        value={profile?.first_name}
        onInput={(evt) =>
          setProfile({ ...profile, first_name: evt.target.value })
        }
      />
    </label>
    <button type="submit">Save</button>
  </form>
);

Merge data into the user profile

const { user } = useRownd();
user.set({
  first_name: 'Alice',
  last_name: 'Ranier',
});

Set a specific field in the user profile

const { user } = useRownd();
user.setValue('first_name', 'Alice');