Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nextjs 13 + with app router #16

Open
AareFabrik opened this issue Aug 12, 2024 · 2 comments
Open

Support for nextjs 13 + with app router #16

AareFabrik opened this issue Aug 12, 2024 · 2 comments

Comments

@AareFabrik
Copy link

Hello

Nice package, it is really useful. But unfortunately I was not able to use it for the new app router for nextjs.

Is there a possibility to make this work?

@kasinskas
Copy link
Owner

kasinskas commented Sep 19, 2024

are you using react-native and react-native-web or just pure next.js?

@kasinskas
Copy link
Owner

kasinskas commented Sep 19, 2024

it's been a while since last time I worked with next, so I'm not familiar with app router yet, but i think i got it working. I'll update the readme with examples and will update rnmq with some helpers like RNMQProvider to make this easier when I have some time, but in the meantime to get app router working this is what needs to be done:

if using react-native + react-native-web + rnmq:

need to update aliases and extensions in next.config:

const nextConfig = {
...
webpack(config) {
    config.resolve.alias = {
      ...(config.resolve.alias || {}),
      "react-native$": "react-native-web",
      "react-native/Libraries/EventEmitter/RCTDeviceEventEmitter$":
        "react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter",
      "react-native/Libraries/vendor/emitter/EventEmitter$":
        "react-native-web/dist/vendor/react-native/emitter/EventEmitter",
      "react-native/Libraries/EventEmitter/NativeEventEmitter$":
        "react-native-web/dist/vendor/react-native/NativeEventEmitter",
    };
    config.resolve.extensions = [
      ".web.js",
      ".web.jsx",
      ".web.ts",
      ".web.tsx",
      ...(config.resolve?.extensions ?? []),
    ];
    return config;
  },
...
}

create or update globals.css with:

html,
body,
#__next {
  width: 100%;
  /* To smooth any scrolling behavior */
  -webkit-overflow-scrolling: touch;
  margin: 0px;
  padding: 0px;
  /* Allows content to fill the viewport and go beyond the bottom */
  min-height: 100%;
}
#__next {
  flex-shrink: 0;
  flex-basis: auto;
  flex-direction: column;
  flex-grow: 1;
  display: flex;
  flex: 1;
}
html {
  scroll-behavior: smooth;
  /* Prevent text size change on orientation change https://gist.github.com/tfausak/2222823#file-ios-8-web-app-html-L138 */
  -webkit-text-size-adjust: 100%;
  height: 100%;
}
body {
  display: flex;
  /* Allows you to scroll below the viewport; default value is visible */
  overflow-y: auto;
  overscroll-behavior-y: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -ms-overflow-style: scrollbar;
}

create RNMQProvider.tsx:

"use client";
import { useServerInsertedHTML } from "next/navigation";
import { StyleSheet } from "react-native";
import { flush } from "react-native-media-query";
export function RNMQProvider({ children }: { children: React.ReactNode }) {
  useServerInsertedHTML(() => {
    const style = flush();
    const sheet = StyleSheet.getSheet();

    return (
      <>
        {style}
        <style
          dangerouslySetInnerHTML={{ __html: sheet.textContent }}
          id={sheet.id}
        />
      </>
    );
  });
  return <>{children}</>;
}

then import RNMQProvider and globals.css into layout.tsx and wrap children with it:

...
import "./globals.css";
import { RNMQProvider } from "./RNMQProvider";
...

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <RNMQProvider>{children}</RNMQProvider>
      </body>
    </html>
  );
}

then use RNMQ as usual:

"use client";

import StyleSheet from "react-native-media-query";
import { Text, View } from "react-native";

const { ids, styles } = StyleSheet.create({
  example: {
    backgroundColor: "green",
    borderRadius: 5,
    "@media (max-width: 1600px) and (min-width: 800px)": {
      backgroundColor: "red",
      borderRadius: 10,
    },
    "@media (max-width: 800px)": {
      backgroundColor: "blue",
      borderRadius: 15,
    },
  },
});

export default function IndexPage() {
  return (
    <View>
      <Text style={styles.example} dataSet={{ media: ids.example }}>
        Hello, world!
      </Text>
    </View>
  );
}

not using rn and rn-web makes this a bit easier:

globals.css from above is not needed

RNMQProvider.tsx looks like this:

"use client";
import { useServerInsertedHTML } from "next/navigation";
import { flush } from "react-native-media-query";
export function RNMQProvider({ children }: { children: React.ReactNode }) {
  useServerInsertedHTML(() => {
    const style = flush();
    return style;
  });
  return <>{children}</>;
}

and then use it:

"use client";
import StyleSheet from "react-native-media-query";

const { ids, styles } = StyleSheet.create({
  example: {
    backgroundColor: "green",
    borderRadius: 5,
    "@media (max-width: 1600px) and (min-width: 800px)": {
      backgroundColor: "red",
      borderRadius: 10,
    },
    "@media (max-width: 800px)": {
      backgroundColor: "blue",
      borderRadius: 15,
    },
  },
});

export default function IndexPage() {
  return (
    <div>
      <p style={styles.example} data-media={ids.example}>
        Hello, world!
      </p>
    </div>
  );
}

let me know if this makes sense. I will look into supporting styling without 'use client', but if you're using react-native-web then I don't think it supports running without 'use client' directive anyway

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants