React Native

Rendering Responses

The createRouterComponent function is used to create the component at the root of a Curi + React application. You can call this component anything that you want, but here it will be referred to as the Router.

createRouterComponent is passed the application's Curi router to create a Router component. The Router will automatically add an observer to the Curi router when it mounts, so that it can re-render when there are new responses.

Along with setting up an observer to react to new responses, the Router sets up contexts for routing values. Theresponse and navigation can be read using the useResponse hook, while the router can be read using the useRouter hook.

import {
  createRouterComponent,
  useRouter,
  useResponse
} from '@curi/react-native';

import router from "./router";
let Router = createRouterComponent(router);

function App() {
  let router = userRouter();
  let {
    response,
    navigation
  } = useResponse();
  let { body:Body } = response;
  return <Body />
}

function MyReactNativeApp = () => (
  <Router>
    <App />
  </Router>
);

What to render

The Router component sets up the application's routing, while its children render the application's content. The Curi router generates response objects from matched locations; those are core for figuring out what to render.

If you use route.respond to set React components as the body properties on your responses, you can create a React element for the body component.

The Body element (it is useful to rename the response's body to Body for JSX transformation) is a placeholder for the "real" component that you render for a route. This means that the "real" component will be different for every route.

While not a strict requirement, it is useful to pass the response object as a prop to the rendered Body component.

function App() {
  let { response } = useResponse();
  let { body:Body } = response;
  return <Body response={response} />
}

function MyReactNativeApp() {
  return (
    <Router>
      <NavLinks />
      <App />
    </Router>
  )
}

If your routes use an object to attach multiple components to a response, the children function also provides a good place to split these apart.

let routes = prepareRoutes([
  {
    name: "Home",
    path: "",
    respond() {
      return {
        body: {
          Main: HomeMain,
          Menu: HomeMenu
        }
      }
    }
  },
  // ...
]);

function App() {
  let { response } = useResponse();
  let { Main, Menu } = response.body;
  return (
    <React.Fragment>
      <Menu />
      <Main response={response} />
    </React.Fragment>
  );
}

The Link component is used to navigate between routes within an application. By default, the Link will render as a TouchableHighlight, but you can specify a different component using the anchor prop.

The Link's name prop describes which route clicking the link should navigate to. If you pass an invalid route name, Curi will warn you.

If a route has any params (or if any of a route's ancestors have params for nested routes), the params prop is used to pass these to the Link.

import { Link } from "@curi/react-native";

let NavLinks = () => (
  <View>
    <Link name="Home">
      <Text>Home</Text>
    </Link>
    <Link name="About" anchor={TouchableOpacity}>
      <Text>About</Text>
    </Link>
    <Link name="User" params={{ id: "blue" }}>
      <Text>Blue</Text>
    </Link>
  </View>
);

The Link also takes hash, query, and state props to attach their values to the location that will be navigated to.

<Link name="Home" hash="details">
  <Text>Home</Text>
</Link>

Please check out the full @curi/react-dom API documentation to see every component that the package provides.

React Native Tips

Back Button

To add back button support, you need to use your history object (which you can access through your router as router.history).

The history.go method is used for jumping between locations, so passing it -1 will jump back to the previous location.

When the app is at the initial location, you may want to return false to close the app when the user presses the back button.

import { BackHandler } from 'react-native';

// create your router
let router = createRouter(browser, routes);

BackHandler.addEventListener(
  "hardwareBackPress",
  () => {
    // close the app when pressing back button
    // while on the initial screen
    if (router.history.index === 0) {
      return false;
    }
    router.history.go(-1);
    return true;
  }
);