Programming Posts - TechOpt.io https://www.techopt.io/category/programming Programming, servers, Linux, Windows, macOS & more Sat, 12 Jul 2025 21:40:27 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 https://www.techopt.io/wp-content/uploads/2024/07/cropped-logo-1-32x32.png Programming Posts - TechOpt.io https://www.techopt.io/category/programming 32 32 Solving Next.js dynamic() Flicker with React.lazy https://www.techopt.io/programming/solving-next-js-dynamic-flicker-with-react-lazy https://www.techopt.io/programming/solving-next-js-dynamic-flicker-with-react-lazy#respond Sat, 12 Jul 2025 21:40:24 +0000 https://www.techopt.io/?p=1039 If you’re working with the Next.js App Router and using the dynamic() function for component-level code splitting, you may have encountered an annoying issue: flickering during rendering of a conditionally-rendered dynamic component. Unfortunately, this is a known issue with the App Router and the dynamic function in Next.js. This behavior can degrade user experience, so […]

The post Solving Next.js dynamic() Flicker with React.lazy appeared first on TechOpt.

]]>
If you’re working with the Next.js App Router and using the dynamic() function for component-level code splitting, you may have encountered an annoying issue: flickering during rendering of a conditionally-rendered dynamic component. Unfortunately, this is a known issue with the App Router and the dynamic function in Next.js. This behavior can degrade user experience, so solving the Next.js dynamic flicker on your website is crucial.

In this post, I’ll break down:

  • Why next/dynamic causes flickering
  • Why it’s worse with nested dynamic components
  • When dynamic() is still safe to use
  • A practical alternative using React.lazy() and Suspense
  • What trade-offs to expect when switching

The Flickering Problem in Next.js

Using dynamic() from next/dynamic is a great way to lazy-load components and reduce your JavaScript bundle size. It also supports options like { ssr: false } to only load components on the client side.

However, when you use these components with the App Router, they often cause a flash of missing or unstyled content, especially during fast navigation or when conditionally rendering dynamic components.

Nested dynamic() calls tend to amplify this issue. For example, a parent component conditionally loading a child via dynamic(), which in turn loads another sub-component dynamically, can make the flickering more severe.

This issue has been reported in GitHub issues and community threads, but a rock-solid fix hasn’t yet made it into the framework.

Interestingly, this flicker seems to affect nested dynamic components more than top-level ones. In my testing, first-level dynamically rendered components used directly in the page file rarely exhibit the issue, which means it’s generally safe to use next/dynamic there to avoid flash of unstyled content (FOUC) during initial mount.

The Better Alternative: React.lazy() + Suspense

One workaround that has proven effective is switching from next/dynamic to native React.lazy() with Suspense. This approach introduces fewer hydration inconsistencies and minimizes flickering, even with nested lazy-loaded components.

Use next/dynamic for components initially rendered on the page, and use React.lazy() for nested components that are rendered conditionally inside those components.

Example 1: Top-level safe usage with next/dynamic

import dynamic from 'next/dynamic';
import { isSignedInAsync } from '../auth';

const PageShell = dynamic(() => import('../components/PageShell'));

export default async function Home() {
  const isSignedIn = await isSignedInAsync();

  if (isSignedIn) return null;

  return <PageShell />;
}

In this example, PageShell is conditionally rendered on the server using dynamic components. This is safe since the dynamic component is rendered with the initial HTML from the server.

Example 2: Nesting with React.lazy() and Suspense

"use client";
import dynamic from 'next/dynamic';

const NestedComponent = dynamic(() => import('./NestedComponent'));

export default function PageShell() {
  const [showNested, setShowNested] = useState(false);

  return (
    <div>
      <h1>Welcome</h1>
      <button onClick={() => setShowNested(true)}>Load Nested Component</button>
      {showNested && (
        <Suspense fallback={<div>Loading nested...</div>}>
          <NestedComponent />
        </Suspense>
      )}
    </div>
  );
}

We can safely use React.lazy() and Suspense inside our dynamically-rendered PageShell component to conditionally render our NestedComponent, and still benefit from lazy-loading and code-splitting.

If we try using the dynamic function instead of React.lazy here, we may get the Next.js dynamic flicker.

Trade-offs of Using React.lazy() Instead of dynamic

While React.lazy() and Suspense often result in smoother rendering, there are two notable downsides:

1. No Server-Side Rendering

Unlike next/dynamic, which lets you disable or enable SSR, React.lazy() only supports client-side rendering. This might hurt SEO if your component needs to be visible to crawlers.

2. Flash of Unstyled Content (FOUC) on Mount

If you do try to use React.lazy() for SSR and use it in the server-rendered HTML, React.lazy() may cause a brief flash of unstyled content because the Next.js bundler doesn’t automatically include the styles for components loaded through React.lazy() in the server-rendered HTML. This limitation can lead to inconsistent rendering.

This is why it’s best to use next/dynamic for components that are visible in the server-rendered HTML, ensuring that styles and structure are present at first paint, while reserving React.lazy() for non-critical or nested components. Using next/dynamic in the initial server-rendered HTML does not seem to cause flickering.

Final Thoughts on Preventing the Next.js Dynamic Flicker

If you’re seeing flickering with next/dynamic and conditional rendering, especially in complex nested layouts, you’re not alone. While the Next.js team continues to evolve App Router, switching to React.lazy() and Suspense where you can may provide a smoother user experience at this time.

To summarize:

  • Use next/dynamic safely for top-level page components
  • Use React.lazy() for nested dynamic imports to reduce flicker

The post Solving Next.js dynamic() Flicker with React.lazy appeared first on TechOpt.

]]>
https://www.techopt.io/programming/solving-next-js-dynamic-flicker-with-react-lazy/feed 0
Fixing ‘Sequence contains more than one matching element’ Android Build https://www.techopt.io/programming/fixing-sequence-contains-more-than-one-matching-element-android-build https://www.techopt.io/programming/fixing-sequence-contains-more-than-one-matching-element-android-build#comments Sun, 06 Jul 2025 01:20:26 +0000 https://www.techopt.io/?p=1024 I just spent the last 3 days wrestling with this “Sequence contains more than one matching element” Android build error: If you noticed from the stack trace above, this is a React Native app. I tried deleting my node_modules folder, deleting my build folders, running ./gradlew clean. I would run the build again and again, […]

The post Fixing ‘Sequence contains more than one matching element’ Android Build appeared first on TechOpt.

]]>
I just spent the last 3 days wrestling with this “Sequence contains more than one matching element” Android build error:

> Task :react-native-device-country:prepareLintJarForPublish
> Task :react-native-device-info:createFullJarRelease
> Task :react-native-device-info:extractProguardFiles
> Task :react-native-device-info:generateReleaseLintModel
> Task :react-native-device-info:prepareLintJarForPublish
> Task :react-native-fbsdk-next:createFullJarRelease
> Task :react-native-fbsdk-next:extractProguardFiles
> Task :app:stripReleaseDebugSymbols
> Task :react-native-fbsdk-next:generateReleaseLintModel
> Task :app:buildReleasePreBundle FAILED
> Task :app:uploadCrashlyticsMappingFileRelease
[Incubating] Problems report is available at: file:///Users/dev/Documents/app/android/build/reports/problems/problems-report.html
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:buildReleasePreBundle'.
> Sequence contains more than one matching element.
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to https://docs.gradle.org/8.14.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.
BUILD FAILED in 1h 6m 21s
1222 actionable tasks: 1208 executed, 14 up-to-date
node:child_process:966
    throw err;
    ^
Error: Command failed: ./gradlew bundleRelease
    at genericNodeError (node:internal/errors:984:15)
    at wrappedFn (node:internal/errors:538:14)
    at checkExecSyncError (node:child_process:891:11)
    at Object.execSync (node:child_process:963:15)
    at /Users/dev/Documents/app/buildscripts/buildserv/build/build-android.js:8:23
    at Object.<anonymous> (/Users/dev/Documents/app/buildscripts/buildserv/build/build-android.js:11:3)
    at Module._compile (node:internal/modules/cjs/loader:1529:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1613:10)
    at Module.load (node:internal/modules/cjs/loader:1275:32)
    at Module._load (node:internal/modules/cjs/loader:1096:12) {
  status: 1,
  signal: null,
  output: [ null, null, null ],
  pid: 22055,
  stdout: null,
  stderr: null
}
Node.js v20.19.3
Cleaning up project directory and file based variables 00:00
ERROR: Job failed: exit status 1

If you noticed from the stack trace above, this is a React Native app. I tried deleting my node_modules folder, deleting my build folders, running ./gradlew clean. I would run the build again and again, but nothing worked. The same error kept popping up every time, right near the end of the build.

No amount of –debug or –stacktrace was giving me any sort of additional information. The most information I could get from this error had already been given to me.

ChatGPT and Copilot were no help, suggesting that this is a Kotlin error and most likely resides in a native library I’m using within the app.

But this didn’t make sense, because I was able to build the project on my local system with the latest dependencies just fine. It was only once I sent the build to my GitLab instance, which runs the build on a macOS VM with gitlab-runner, that I started getting this error.

So is the error with the build process, or one of the build tools itself?

Narrowing Down the Cause

After a ton of googling of this error, I finally came across this Google IssueTracker post that pointed me in the right direction. This person describes the exact same issue I’m having.

This person also says that this error started happening after an upgrade to AGP 8.9.0.

Now we’re getting somewhere. It doesn’t look like they’re using React Native, but at this point I was confident the issue isn’t stemming from anything to do with React Native.

AGP is an Android build tool. It’s possible that my macOS VM has a newer version of AGP than my local system does. This would explain why it’s only happening once I send the app to build in the macOS VM.

So, what’s the problem?

Well, it can be traced back to this section here in the app’s build.gradle:

...
splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
...

This section of the build.gradle file tells gradle to output different APK files for different CPU architectures.

When this part of the build.gradle file is encountered by running the bundleRelease gradle task, the “sequence contains more than one matching element” exception is thrown because bundleRelease expects to be generating a single universal AAB file instead of separate APK files, that can then be uploaded to the Google Play Store.

The Fix

All I did was remove this section from our build.gradle file:

...
splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
...

And it resolved the issue! We weren’t using the multiple APKs anyways, so I’m not even sure why we had this in our build.gradle file. We only upload the single universal AAB to the Play Store.

Additional Notes

In the issue tracker linked above, Google states that they do not plan on fixing this, since they don’t officially support creating multiple APKs when running bundleRelease. However, if you still need multiple APK support, someone on the issue tracker suggests the following fix:

splits {
        abi {
            // Detect app bundle and conditionally disable split abis
            // This is needed due to a "Sequence contains more than one matching element" error
            // present since AGP 8.9.0, for more info see:
            // https://issuetracker.google.com/issues/402800800

            // AppBundle tasks usually contain "bundle" in their name
            val isBuildingBundle = gradle.startParameter.taskNames.any { it.lowercase().contains("bundle") }

            // Disable split abis when building appBundle
            isEnable = !isBuildingBundle

            reset()
            //noinspection ChromeOsAbiSupport
            include("armeabi-v7a", "arm64-v8a", "x86_64")

            isUniversalApk = true
        }
}

This enables APK splitting while disabling APK splitting for the bundleRelease task, preventing the “sequence contains more than one matching element” error.

The post Fixing ‘Sequence contains more than one matching element’ Android Build appeared first on TechOpt.

]]>
https://www.techopt.io/programming/fixing-sequence-contains-more-than-one-matching-element-android-build/feed 2
React Native vs Flutter in 2025: Which to Choose for a New App https://www.techopt.io/programming/react-native-vs-flutter-in-2025-which-to-choose-for-a-new-app https://www.techopt.io/programming/react-native-vs-flutter-in-2025-which-to-choose-for-a-new-app#respond Sat, 03 May 2025 19:56:02 +0000 https://www.techopt.io/?p=919 When you’re building a cross-platform mobile app in 2025, one of the first questions is React Native vs Flutter: which framework should you choose? Both are powerful cross-platform tools. They let you build for iOS and Android from a shared codebase. But for long-term success, React Native is the better option in most cases. Performance […]

The post React Native vs Flutter in 2025: Which to Choose for a New App appeared first on TechOpt.

]]>
When you’re building a cross-platform mobile app in 2025, one of the first questions is React Native vs Flutter: which framework should you choose? Both are powerful cross-platform tools. They let you build for iOS and Android from a shared codebase. But for long-term success, React Native is the better option in most cases.

Performance Is No Longer the Dealbreaker

In the past, Flutter outperformed React Native due to its direct rendering model. React Native used a bridge that communicated asynchronously between JavaScript and native code. This used to cause performance bottlenecks. Today, things have changed.

React Native’s new architecture has narrowed the gap. With the Fabric rendering engine and TurboModules, apps now run with near-native speed. Interactions and animations are smooth. The old performance argument simply doesn’t apply anymore.

Hermes, a lightweight JavaScript engine, further improves speed. It reduces memory usage and startup times. React Native apps now feel fast and efficient.

Issues like navigation lag or gesture delays have mostly disappeared. Thanks to Reanimated and Gesture Handler by Software Mansion, modern React Native apps rival the performance of native Swift or Kotlin apps.

UI Flexibility and Customization

Flutter uses with Google’s Material Design by default. It’s polished and consistent, but it can feel restrictive. If you want a unique design or to match native iOS components, Flutter takes more effort.

React Native, on the other hand, gives you a blank canvas. It renders real native components. This means your app looks and behaves like a native app on each platform.

Customization in React Native is straightforward. You can easily build your own components or bring in existing native modules. Want to use Swift or Kotlin? No problem.

There are also countless libraries that give you freedom over design. React Native Paper or Nativewind libraries all help developers build beautiful UIs without limitations. Tailwind CSS is a popular option for web developers in 2025, and Nativewind allows developers to use Tailwind CSS to style their React Native components.

Libraries will help give you a quick-start with React Native; but even if you don’t want to use a UI library, it’s generally quicker and easier to achieve the look you’re going for with React Native.

Apps with demanding UX needs benefit here. Whether you want to follow iOS’s Cupertino look, Android’s native style, or go for a completely custom look, React Native makes it easier.

Community, Adoption, and Real-World Usage

React Native has a massive and experienced community. It’s used by Discord, Shopify, Microsoft, Walmart, and many others. These companies have built large-scale apps and actively contribute to the ecosystem. You can see a more extensive list in the React Native Showcase.

Flutter is still growing. It’s backed by Google and has seen adoption in some sectors, but it’s less common in enterprise apps. Yes, Flutter does have an impressive showcase of its own, with a lot of popular companies using it. But the biggest companies are still choosing React Native.

More developers and teams rely on React Native. That means better tools, more tutorials, more plugins, and faster support. Need to hire? You’ll find it easier to find experienced React Native developers.

React Native meetups, conferences, and job listings still outnumber Flutter’s. It’s the more mature option for serious production apps.

JavaScript/TypeScript vs Dart

React Native is powered by JavaScript and TypeScript. Most developers already know these languages. The ecosystem is enormous. You can find libraries, tools, and community help for just about anything.

Flutter uses Dart. It’s improved over time and offers some nice features. But it’s still niche. Fewer developers know Dart, and fewer tools exist for it.

Using JS/TS also makes it easier to integrate with full-stack solutions. Node.js for backend, React for web, and React Native for mobile? You can reuse code across all of them.

For team productivity and long-term maintenance, JavaScript and TypeScript have the edge.

Better Web and Desktop Pathways

React Native is mobile-first but has solid web support through React Native for Web. Combined with React for traditional websites, you get a unified developer experience.

Flutter officially supports web and desktop, but real-world usage is limited. Web performance is hit or miss. The experience often feels heavy and not optimized for browsers.

React Native’s ecosystem supports better CI/CD and deployment too. Tools like Expo and Fastlane streamline everything from build to publish.

Project Longevity and Trust

Google has ended many popular projects before. Think Google Reader, Stadia, or the Chromecast. That uncertainty affects how developers view Flutter.

Meta backs React Native. Could they pull back? Possibly. But the difference is that React Native has critical mass. Even if Meta dropped it tomorrow, the community would keep it alive. Many companies depend on it.

Microsoft has even built React Native for Windows and macOS. That means React Native is not just a Meta project anymore—it’s supported by multiple big players.

This gives it a much stronger foundation for long-term stability.

Rich Ecosystem and Tooling

React Native has everything you need. Navigation with React Navigation. State management with Redux or Zustand. Animations with Reanimated or Lottie. It all fits together.

You can develop faster with Expo. You get reliable TypeScript support. Debugging is better too. Flipper and Chrome DevTools make the developer experience smoother.

Third-party integrations like Stripe, Firebase, and Google Maps are easier to implement. They’re better documented and more widely tested in React Native.

React Native vs Flutter: React Native Wins in 2025

So, in the battle of React Native vs Flutter, React Native still leads in 2025.

It offers better performance than ever before. It’s easier to customize, more widely adopted, and backed by a huge community. You get the benefits of the JS/TS ecosystem and peace of mind with long-term support.

Flutter is a solid choice in some scenarios, especially if you’re deep in the Google ecosystem. But for most teams, React Native remains the best bet.

If you’re launching a new app, React Native gives you speed, flexibility, and staying power. It’s the smarter investment for today, and for the future.

The post React Native vs Flutter in 2025: Which to Choose for a New App appeared first on TechOpt.

]]>
https://www.techopt.io/programming/react-native-vs-flutter-in-2025-which-to-choose-for-a-new-app/feed 0
React Conditional Rendering: Logical AND vs Ternary Operator https://www.techopt.io/programming/react-conditional-rendering-logical-and-vs-ternary-operator https://www.techopt.io/programming/react-conditional-rendering-logical-and-vs-ternary-operator#respond Tue, 01 Apr 2025 22:30:57 +0000 https://www.techopt.io/?p=877 After building countless React and React Native components, I’ve run into one too many frustrating bugs caused by the logical AND (&&) operator used for conditional rendering in JSX. These issues are often subtle and hard to track down, so I’ve made it a rule: I don’t use logical AND for conditional rendering in JSX […]

The post React Conditional Rendering: Logical AND vs Ternary Operator appeared first on TechOpt.

]]>
After building countless React and React Native components, I’ve run into one too many frustrating bugs caused by the logical AND (&&) operator used for conditional rendering in JSX. These issues are often subtle and hard to track down, so I’ve made it a rule: I don’t use logical AND for conditional rendering in JSX anymore. Instead, I stick with the ternary (conditional) operator (in other words, shorthand “if” statement). It’s safer, clearer, and avoids nasty surprises.

The Problem with Logical AND for Conditional Rendering

Here’s a typical use case with logical AND:

{user.age && <Text>{`Age: ${user.age}`}</Text>}

You might expect this to only render the Text element if user.age is defined, or above 0 (since 0 is a falsy value in JavaScript).

But consider what happens if user.age is 0 (a valid, real-world age). We don’t want the <Text> element to get rendered in this case, and it doesn’t.

However, it creates a pretty unwanted side effect:

  • 0 && <Text>...</Text> evaluates to 0.
  • React will render the value 0 directly, essentially interpreting it as text instead of a boolean value!
    • In React Native, this is even worse: it will actually crash the entire application with an error about trying to render text outside of a <Text> component!

Example:

const user = { age: 0 };

return (
  <View>
    {user.age && <Text>{`Age: ${user.age}`}</Text>}
  </View>
);

What renders: Just 0. Not the <Text> element.

This happens because && doesn’t enforce a boolean context; it returns the first falsy value or the last truthy value. That means non-boolean values like 0 or "" can sneak through and show up unexpectedly. This can also crash your entire application in the case of React Native!

A Better Alternative: The Ternary Operator (Shorthand “if” Statements)

Instead, I use the ternary (conditional) operator, which makes the intent clearer and avoids rendering unwanted values:

{user.age ? <Text>{`Age: ${user.age}`}</Text> : null}

This guarantees that only a JSX element or null will be rendered; no accidental numbers or strings appearing in your layout.

Improved Example:

const user = { age: 0 };

return (
  <View>
    {user.age ? <Text>{`Age: ${user.age}`}</Text> : null}
  </View>
);

What renders: Nothing if age is undefined, null or 0, and the full Text block if it’s any other number.

Summary: Use the Ternary Operator for Conditional Rendering in React

While using && for conditional rendering may seem like a shortcut, it’s not always safe. This is especially true when your condition might evaluate to a falsy non-boolean like 0. From my experience, using the ternary operator leads to fewer bugs and a more predictable UI.

✅ Use:

condition ? <Component /> : null

🚫 Avoid:

condition && <Component />

When writing JSX in React or React Native, I choose clarity over cleverness. The ternary operator keeps my components clean and my debugging sessions short!

The post React Conditional Rendering: Logical AND vs Ternary Operator appeared first on TechOpt.

]]>
https://www.techopt.io/programming/react-conditional-rendering-logical-and-vs-ternary-operator/feed 0
App Center Alternatives for React Native Developers https://www.techopt.io/programming/app-center-alternatives-for-react-native-developers https://www.techopt.io/programming/app-center-alternatives-for-react-native-developers#respond Sun, 16 Mar 2025 02:47:39 +0000 https://www.techopt.io/?p=833 Microsoft’s decision to discontinue and sunset App Center has left many React Native developers searching for reliable alternatives. If you’ve been using App Center for building, testing, and distributing your apps, it’s time to explore new solutions. In this guide, we’ll break down the best App Center alternatives to help you keep your workflow efficient […]

The post App Center Alternatives for React Native Developers appeared first on TechOpt.

]]>
Microsoft’s decision to discontinue and sunset App Center has left many React Native developers searching for reliable alternatives. If you’ve been using App Center for building, testing, and distributing your apps, it’s time to explore new solutions. In this guide, we’ll break down the best App Center alternatives to help you keep your workflow efficient and uninterrupted.

Why Is App Center Being Discontinued?

App Center has been a go-to choice for mobile developers, providing CI/CD capabilities, automated testing, and distribution for iOS and Android apps. However, Microsoft has decided to sunset the platform, leaving teams to find replacement services that meet their needs. Therefore, selecting the right alternative is crucial. The key factors in choosing an alternative include build automation, real-device testing, seamless app distribution, and over-the-air (OTA) updates.

Best App Center Alternatives for React Native

1. EAS (Expo Application Services)

For teams using EAS, it provides an all-in-one solution for building, updating, and distributing React Native apps. As a result, it is one of the best alternatives to App Center, especially for projects already leveraging Expo.

  • Pros:
    • Seamless integration with Expo projects
    • No need for local machine setup
    • Cloud-based builds for iOS and Android
    • EAS Update serves as an alternative to CodePush, allowing for seamless OTA updates
  • Cons:
    • Primarily geared toward Expo-managed projects
    • Limited flexibility for bare React Native apps

2. Hot Updater (Self-Hosted CodePush Alternative)

If you relied on App Center for CodePush, a crucial feature for deploying over-the-air updates, you need a replacement. Fortunately, one of the best open-source alternatives is Hot Updater. This is my personal favourite CodePush replacement. It provides similar functionality while allowing you to self-host your own OTA update solution.

  • Pros:
    • Self-hosted, offering full control over updates
    • Supports both iOS and Android
    • Intuitive web console for managing versions
    • Plugin support for various storage providers (AWS S3, Supabase, etc.)
  • Cons:
    • Requires infrastructure setup and maintenance
    • Needs DevOps expertise for proper implementation

3. Bitrise

Bitrise is one of the most popular CI/CD platforms for mobile development. It offers cloud-based automation, supports React Native out of the box, and provides a flexible pipeline system for building, testing, and deploying apps. Consequently, many teams transitioning from App Center have found it to be a reliable alternative.

  • Pros:
    • Pre-configured workflows for React Native
    • Easy integration with GitHub, GitLab, and Bitbucket
    • Supports both iOS and Android
  • Cons:
    • Limited free-tier resources
    • Learning curve for advanced workflow customization

4. Codemagic

Codemagic is another excellent CI/CD tool that specializes in mobile development. It supports React Native projects and simplifies the build and deployment process with minimal configuration. Additionally, its user-friendly approach makes it a strong choice for teams looking for a quick transition.

  • Pros:
  • Cons:
    • Can get expensive for teams with heavy usage
    • Limited concurrent builds on the free plan

5. Firebase App Distribution

If your primary need is distributing pre-release versions of your app, Firebase App Distribution is a great alternative to App Center’s distribution feature. Moreover, it integrates well with other Firebase tools, making it an appealing choice for teams already using Firebase.

  • Pros:
    • Easy tester management
    • Integrates with Firebase Crashlytics for monitoring
    • Works for both iOS and Android
  • Cons:
    • No built-in CI/CD
    • Requires additional tools for automated builds

Choosing the Right App Center Alternative for Your React Native Project

The best App Center alternative depends on your specific needs:

As App Center sunsets, transitioning to a new platform early will help ensure a smooth workflow. Consequently, by selecting the right alternative, you can continue to build, test, distribute, and update your React Native apps with minimal disruption.

The post App Center Alternatives for React Native Developers appeared first on TechOpt.

]]>
https://www.techopt.io/programming/app-center-alternatives-for-react-native-developers/feed 0
When to Use (and Not Use) Tailwind CSS in 2025 https://www.techopt.io/programming/when-to-use-and-not-use-tailwind-css-in-2025 https://www.techopt.io/programming/when-to-use-and-not-use-tailwind-css-in-2025#comments Sun, 23 Feb 2025 22:11:20 +0000 https://www.techopt.io/?p=819 Introduction Tailwind CSS has solidified its place in the modern web development ecosystem, offering a utility-first approach that streamlines styling for complex projects. While Tailwind is a powerful tool, it’s not a one-size-fits-all solution. In 2025, Tailwind is more popular than ever, but there are cases where it may not be the best choice. Let’s […]

The post When to Use (and Not Use) Tailwind CSS in 2025 appeared first on TechOpt.

]]>
Introduction

Tailwind CSS has solidified its place in the modern web development ecosystem, offering a utility-first approach that streamlines styling for complex projects. While Tailwind is a powerful tool, it’s not a one-size-fits-all solution. In 2025, Tailwind is more popular than ever, but there are cases where it may not be the best choice. Let’s break down when to use Tailwind, and when to consider alternatives.

When to Use Tailwind CSS

1. Complex, Multi-Page Websites

Tailwind shines in large-scale, multi-page applications where design consistency is critical. With reusable utility classes, developers can ensure a unified UI without wrestling with conflicting styles from separate CSS files. Platforms like SaaS applications, dashboards, and content-heavy websites benefit immensely from Tailwind’s scalable approach.

2. Rapid Prototyping

If speed is a priority, Tailwind helps teams iterate faster. Its utility classes allow developers to style components directly in markup, reducing the need for custom CSS. This makes it ideal for MVPs, startup projects, and proof-of-concept applications where time-to-market is crucial.

3. Projects Requiring Design System Enforcement

Tailwind is a great fit for teams that need strict adherence to a design system. The ability to define custom themes, typography, and color palettes in the tailwind.config.js file ensures that styles remain consistent across all pages and components.

Tailwind CSS version 4, which was just released, takes this a step further. This new version of Tailwind allows for most configuration to be done right inside of your main CSS file.

4. Component-Based Frameworks (React, Vue, Svelte, Next.js, etc.)

For teams using modern frameworks, Tailwind works seamlessly with component-driven development. It allows styling to live alongside the component logic, promoting maintainability and reducing CSS file bloat.

5. Web Apps with a Long Development Lifecycle

Maintaining large applications is easier with Tailwind since it reduces CSS complexity. Unlike traditional CSS or preprocessor-based approaches, Tailwind minimizes global styles, making it easier to refactor and extend applications over time.

When Not to Use Tailwind CSS

1. Small, Static Websites or Simple Landing Pages

For one-page websites or simple marketing pages, Tailwind may be overkill. A minimal custom CSS file or even plain HTML/CSS may suffice. Using Tailwind in such cases could add unnecessary overhead without significant benefits.

2. Highly Unique, Artistic Designs

While Tailwind is flexible, highly creative or experimental designs with intricate animations, custom typography, and complex layouts might be better served with traditional CSS, SCSS, or CSS-in-JS. Tailwind’s structured approach may feel limiting for designers who prefer complete freedom over styles.

3. Teams Without Tailwind Experience

Despite its advantages, Tailwind has a learning curve. Developers unfamiliar with its utility-first approach may struggle initially. If a team lacks experience or doesn’t have time to invest in learning Tailwind, sticking to traditional CSS methodologies may be more efficient.

4. Legacy Codebases with Predefined Styles

If you’re working on a legacy project that already has well-structured CSS or a component library, integrating Tailwind could introduce inconsistencies and unnecessary complexity. Migrating to Tailwind in such cases should be a carefully considered decision.

5. Strict SEO or Performance-Optimized Websites Where Every KB Counts

While Tailwind’s PurgeCSS ensures minimal CSS footprint, in some ultra-performance-critical cases, writing minimal, handcrafted CSS might still be preferable. Projects that need to prioritize reducing external dependencies might opt for vanilla CSS instead.

Conclusion: When to use Tailwind CSS in 2025

Tailwind CSS is a top choice for complex, multi-page applications, design-consistent systems, and component-driven frameworks in 2025. However, it’s not always the best tool for every scenario.

For small static sites, highly creative designs, or legacy projects, traditional CSS approaches may still hold an advantage. Understanding when to use Tailwind, and when not to, will help you maximize efficiency while maintaining flexibility in your web development workflow.

The post When to Use (and Not Use) Tailwind CSS in 2025 appeared first on TechOpt.

]]>
https://www.techopt.io/programming/when-to-use-and-not-use-tailwind-css-in-2025/feed 2
Five Important Technical SEO Tips for 2025 https://www.techopt.io/programming/five-important-technical-seo-tips-for-2025 https://www.techopt.io/programming/five-important-technical-seo-tips-for-2025#respond Thu, 02 Jan 2025 14:37:00 +0000 https://www.techopt.io/?p=641 As we step into 2025, staying ahead in the digital landscape requires adopting cutting-edge practices. To help you optimize your website, here are five important technical SEO tips for 2025 that will enhance your site’s performance and search visibility. From improving loading speeds to balancing lazy loading and server-side rendering, these tips will ensure your […]

The post Five Important Technical SEO Tips for 2025 appeared first on TechOpt.

]]>
As we step into 2025, staying ahead in the digital landscape requires adopting cutting-edge practices. To help you optimize your website, here are five important technical SEO tips for 2025 that will enhance your site’s performance and search visibility. From improving loading speeds to balancing lazy loading and server-side rendering, these tips will ensure your website meets modern SEO standards.

As a web developer, part of our job is to make sure we’re using available optimizations and adhering to the latest best coding practices. Many of these optimizations rely heavily on clever use of HTML and JavaScript, so technical expertise is key.

1. Optimize LCP Loading Speed

Largest Contentful Paint (LCP) is a critical metric in Google’s Core Web Vitals. It measures the time it takes for the largest visible content element—usually an image or block of text—to load and become visible to users. A slow LCP can negatively impact user experience and search rankings.

To improve LCP:

  • Avoid lazy loading the largest image or hero image on your page. This ensures the browser can prioritize its rendering immediately.
  • Use efficient image formats like WebP or AVIF for better compression.
  • Preload critical resources, such as fonts and above-the-fold images, to help the browser fetch them early.

These changes often involve direct modifications to your HTML structure and strategic resource management through JavaScript to ensure optimized delivery.

2. Lazy Load Other Images

While the largest image should not be lazy-loaded, smaller images and those below the fold can and should be. Lazy loading these assets reduces the initial page size and improves loading speed, leading to a better user experience and higher SEO performance.

Use the loading="lazy" attribute for images or leverage JavaScript libraries for more control. For example:

<img src="example.jpg" loading="lazy" alt="Descriptive Alt Text">

Strategic use of HTML attributes and JavaScript allows you to control how and when resources load, ensuring optimal performance.

3. Lazy Load Unnecessary JavaScript and Unnecessary Content Below the Fold

Lazy loading isn’t just for images—you can also apply it to JavaScript and other content below the fold. This minimizes the amount of resources the browser processes initially, reducing the time to interactive (TTI).

Here’s an example using React:

import React, { lazy, Suspense } from 'react';

const LoginModal = lazy(() => import('./LoginModal'));

function App() {
  const [showModal, setShowModal] = React.useState(false);

  return (
    <div>
      <button onClick={() => setShowModal(true)}>Open Login</button>
      {showModal && (
        <Suspense fallback={<div>Loading...</div>}>
          <LoginModal />
        </Suspense>
      )}
    </div>
  );
}

This approach defers loading the login modal until the user clicks the button. Frameworks like Vue, Angular, or vanilla JavaScript also support similar lazy loading techniques using import(), which you can read more about here.

Implementing these optimizations requires careful use of JavaScript to balance resource management and functionality.

4. Don’t Lazy Load Content Vital to Search Engines

While lazy loading has its benefits, overusing it can backfire. Content critical for SEO, like metadata, structured data, and primary text visible to users, should not be lazy-loaded. Search engines may not fully index this content, harming your rankings.

To ensure vital information is always available:

  • Use Server-Side Rendering (SSR) for pages you need to rank well in search engines. SSR renders content on the server before sending it to the browser, ensuring it’s accessible to search engines and users.
  • Prioritize preloading critical content while deferring less essential resources.

This balance often involves designing your HTML to ensure critical content is included upfront and leveraging JavaScript for secondary features. Therefore, avoid over-optimization that can harm your site’s accessibility and SEO.

5. Minimize Time to Interactive

Time to Interactive (TTI) measures how quickly a page becomes fully interactive. High TTI can frustrate users and impact rankings.

To optimize TTI:

  • Use SSR to render the initial view faster.
  • Choose smaller, lightweight JavaScript libraries and avoid running unnecessary scripts on load.
  • Combine lazy loading with efficient bundling to defer non-critical scripts until needed.

Reducing TTI requires fine-tuning your JavaScript execution and crafting your HTML to load essential resources efficiently. By optimizing these elements, you can enhance user satisfaction and meet Google’s performance benchmarks.

Conclusion

By following these five technical SEO tips for 2025, you can improve your site’s speed, usability, and search engine visibility. Many of these strategies rely on making deliberate adjustments to your HTML and JavaScript to strike the perfect balance between performance and accessibility. Stay proactive, and your website will thrive in the ever-changing SEO landscape.

The post Five Important Technical SEO Tips for 2025 appeared first on TechOpt.

]]>
https://www.techopt.io/programming/five-important-technical-seo-tips-for-2025/feed 0
Share Code Between React and React Native Projects https://www.techopt.io/programming/share-code-between-react-and-react-native-projects https://www.techopt.io/programming/share-code-between-react-and-react-native-projects#respond Fri, 27 Dec 2024 16:43:50 +0000 http://localhost:8080/?p=96 Sharing code between React and React Native projects improves development efficiency and ensures consistency. While UI code cannot always be shared (unless using react-native-web), you can reuse a lot of logic, such as context management, Redux stores, and utility functions. This approach helps reduce redundant work and streamlines project maintenance. Let’s dive into three methods […]

The post Share Code Between React and React Native Projects appeared first on TechOpt.

]]>
Sharing code between React and React Native projects improves development efficiency and ensures consistency. While UI code cannot always be shared (unless using react-native-web), you can reuse a lot of logic, such as context management, Redux stores, and utility functions. This approach helps reduce redundant work and streamlines project maintenance. Let’s dive into three methods to share code between React and React Native projects.

Why Share Code Between React and React Native?

React and React Native share the same core library, making it possible to reuse logic like hooks, contexts, and state management. By sharing code, you reduce development time and avoid duplicating functionality. This is especially helpful for projects that have both a web app and a mobile app with overlapping features.

However, sharing presentation components remains a challenge due to platform differences. Instead, focus on sharing non-UI elements like business logic, data processing, and utility functions.

Methods to Share Code Between React and React Native

1. Using a Monorepo

A monorepo centralizes multiple projects, such as your React app, React Native app, and shared logic, into a single repository. This structure simplifies managing shared code.

Advantages:

  • Centralized control over shared logic.
  • Simplified versioning with everything in one place.
  • Dependency management becomes easier using tools like Yarn Workspaces or Lerna.

How It Works:

  • Organize your repository into separate folders for the React app, React Native app, and shared code.
  • Link the shared code using a package manager like Yarn.
  • Import shared modules in your apps directly as local dependencies.

2. Using NPM Packages

Publishing shared logic as NPM packages provides a modular and flexible approach. These packages can either be hosted publicly on npmjs or in a private repository.

Why This Method Works Well:

  • Shared logic stays modular and independent.
  • Updating shared logic becomes seamless by bumping the package version in dependent projects.
  • Packages can easily be reused in other projects, even outside the React ecosystem.

How to Set It Up:

  1. Create a separate repository for shared logic.
  2. Develop your code and package it with tools like Rollup or Webpack if needed.
  3. Publish the package to npmjs or a private NPM registry.
  4. Install the package in both React and React Native projects.

Example:

// Inside shared-package.js
export function calculateDiscount(price, discount) {
  return price - price * (discount / 100);
}

// React App
import { calculateDiscount } from "my-shared-package";

// React Native App
import { calculateDiscount } from "my-shared-package";

This is personally one of my top methods for code sharing as I find it makes sharing complex code between React and React Native super clean and easy.

3. Good Old Copy and Paste

For small, one-off functions that are unlikely to change, copy-pasting offers a simple and fast solution. Although this method lacks scalability, it can work for minor use cases.

When to Use This Method:

  • The code is minimal and unlikely to evolve.
  • You need a quick solution for prototyping or experimentation.

Drawbacks:

  • Maintenance becomes challenging if changes are needed later.
  • Inconsistencies may arise if similar logic exists across multiple projects.

Example:

// Copied and pasted in both projects
function formatCurrency(amount) {
  return `$${amount.toFixed(2)}`;
}

Remarks

  • Choose your method based on the complexity of shared logic and project requirements.
  • NPM packages strike a good balance between flexibility and maintainability.
  • Monorepos suit tightly coupled projects but may increase setup complexity.
  • Minimize reliance on copy-pasting to avoid long-term maintenance issues.

By adopting these strategies, you can efficiently share code between React and React Native projects, reducing duplication and creating a cohesive development workflow.

The post Share Code Between React and React Native Projects appeared first on TechOpt.

]]>
https://www.techopt.io/programming/share-code-between-react-and-react-native-projects/feed 0
Handle Edge-to-Edge in React Native Android 15 (API 35) https://www.techopt.io/programming/handling-edge-to-edge-react-native-android-15 https://www.techopt.io/programming/handling-edge-to-edge-react-native-android-15#respond Thu, 19 Dec 2024 18:54:00 +0000 https://www.techopt.io/?p=526 With the release of Android 15 (API 35) and React Native 0.76, edge-to-edge layouts have become the default for modern Android apps. This change emphasizes the importance of handling safe area insets properly. If you’ve relied on React Native’s SafeAreaView, you’ve likely discovered that it doesn’t work on Android, as it was only designed with […]

The post Handle Edge-to-Edge in React Native Android 15 (API 35) appeared first on TechOpt.

]]>
With the release of Android 15 (API 35) and React Native 0.76, edge-to-edge layouts have become the default for modern Android apps. This change emphasizes the importance of handling safe area insets properly. If you’ve relied on React Native’s SafeAreaView, you’ve likely discovered that it doesn’t work on Android, as it was only designed with iOS’s notch in mind. Thankfully, the react-native-safe-area-context library offers a cross-platform solution that supports both Android and iOS.

In this article, we’ll walk you through the steps to replace SafeAreaView with View and utilize react-native-safe-area-context to ensure your layouts adapt to safe area insets correctly on Android.

Steps to Adapting Layout for Edge-to-Edge in React Native Android 15 (API 35)

1. Install the react-native-safe-area-context Library

If you haven’t already, add the library to your project using either npm or Yarn:

npm install react-native-safe-area-context

or

yarn add react-native-safe-area-context

2. Wrap your App with SafeAreaProvider

Add the SafeAreaProvider component to the root of your app and provide initialWindowMetrics to improve performance and avoid layout jumps on startup.

You can retrieve initialWindowMetrics from react-native-safe-area-context.

import React from 'react';
import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context';
import MyApp from './MyApp';

const App = () => (
  <SafeAreaProvider initialMetrics={initialWindowMetrics}>
    <MyApp />
  </SafeAreaProvider>
);

export default App;

3. Use Safe Area Insets Padding on Outer Views to Push Content out of Screen Edge

You can get child content to push into the safe area away from the screen edges by using padding on the outermost view. You should use useSafeAreaInsets for functional components, and withSafeAreaInsets for class components.

Examples

Functional Component

Here’s how to use the useSafeAreaInsets hook in a functional component:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

const MyFunctionalComponent: React.FC = () => {
  const insets = useSafeAreaInsets();

  return (
    <View
      style={{
        ...styles.container,
        paddingTop: insets.top,
        paddingBottom: insets.bottom,
        paddingLeft: insets.left,
        paddingRight: insets.right,
      }}
    >
      <Text>Hello, world!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

export default MyFunctionalComponent;
Class Component

Here’s how to use the withSafeAreaInsets higher-order component (HOC) in a class component:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { withSafeAreaInsets, SafeAreaInsetsContext } from 'react-native-safe-area-context';

interface Props {
  insets: SafeAreaInsetsContext;
}

class MyClassComponent extends React.Component<Props> {
  render() {
    const { insets } = this.props;

    return (
      <View
        style={{
          ...styles.container,
          paddingTop: insets?.top,
          paddingBottom: insets?.bottom,
          paddingLeft: insets?.left,
          paddingRight: insets?.right,
        }}
      >
        <Text>Hello, world!</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

export default withSafeAreaInsets(MyClassComponent);

That’s it! You can also decide which sides (top, bottom, left and right) you want to apply padding to based on the design of your screen. If you’re not sure, applying it to all sides and seeing how the screen looks is best.

Remarks

  • While react-native-safe-area-context exports a SafeAreaView component, our experience indicates that it can also lead to screen jumping issues, especially on iOS. Therefore, it’s still better to use the useSafeAreaInsets hook for functional components or the withSafeAreaInsets HOC for class components.
  • Passing initialWindowMetrics to SafeAreaProvider ensures accurate safe area insets on app startup, preventing layout jumps caused by delayed inset calculations.
  • For testing, you’ll want to use an Android emulator or phone that supports edge-to-edge and is running at least Android 15 (API 35), such as the Google Pixel 8.
  • If you were previously using SafeAreaView from react-native for iOS, you should remove all instances of SafeAreaView from your code. You can cross-reference our iOS guide here.

The post Handle Edge-to-Edge in React Native Android 15 (API 35) appeared first on TechOpt.

]]>
https://www.techopt.io/programming/handling-edge-to-edge-react-native-android-15/feed 0
Fix Screen Jumping Using SafeAreaView in React Native https://www.techopt.io/programming/fix-screen-jumping-safeareaview-react-native https://www.techopt.io/programming/fix-screen-jumping-safeareaview-react-native#respond Sun, 15 Dec 2024 00:10:03 +0000 https://www.techopt.io/?p=515 Screen jumping or flickering on mount is a common frustration when using SafeAreaView in iOS with React Native, specifically on devices with a notch or Dynamic Island. As these features are becoming increasingly common and now represent the majority of devices sold, addressing this issue is critical to ensure a smooth user experience. This problem, […]

The post Fix Screen Jumping Using SafeAreaView in React Native appeared first on TechOpt.

]]>
Screen jumping or flickering on mount is a common frustration when using SafeAreaView in iOS with React Native, specifically on devices with a notch or Dynamic Island. As these features are becoming increasingly common and now represent the majority of devices sold, addressing this issue is critical to ensure a smooth user experience. This problem, often referred to as “jumping SafeAreaView,” can interrupt the smooth user experience your app should deliver.

Thankfully, there’s a straightforward solution: replace SafeAreaView from the react-native library with View and leverage the react-native-safe-area-context library to handle safe area insets in a more optimized way.

In this article, we will guide you on how to implement this fix using TypeScript or JavaScript for both functional and class components.

Why Does Jumping with SafeAreaView Occur?

The screen jumping issue with SafeAreaView happens because of its initial rendering behavior on iOS. It’s unable to consistently calculate safe area insets before the content mounts, causing a noticeable flicker.

The react-native-safe-area-context library optimizes this process under the hood, ensuring a smoother rendering experience regardless of the device.

Steps to Fixing Screen Jumping when using SafeAreaView

1. Install the react-native-safe-area-context Library

If you haven’t already, add the library to your project using either npm or Yarn:

npm install react-native-safe-area-context

or

yarn add react-native-safe-area-context

2. Wrap your App in SafeAreaProvider

Add the SafeAreaProvider component to the root of your app and provide initialWindowMetrics to improve performance and avoid layout jumps on startup.

You can retrieve initialWindowMetrics from react-native-safe-area-context.

import React from 'react';
import { SafeAreaProvider, initialWindowMetrics } from 'react-native-safe-area-context';
import MyApp from './MyApp';

const App = () => (
  <SafeAreaProvider initialMetrics={initialWindowMetrics}>
    <MyApp />
  </SafeAreaProvider>
);

export default App;

3. Replace Instances of SafeAreaView with Padding Using Safe Area Insets

You should replace all instances of SafeAreaView throughout your application with insets using useSafeAreaInsets for functional components, or withSafeAreaInsets for class components.

Examples

Functional Component

Here’s how to use the useSafeAreaInsets hook in a functional component:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

const MyFunctionalComponent: React.FC = () => {
  const insets = useSafeAreaInsets();

  return (
    <View
      style={{
        ...styles.container,
        paddingTop: insets.top,
        paddingBottom: insets.bottom,
        paddingLeft: insets.left,
        paddingRight: insets.right,
      }}
    >
      <Text>Hello, world!</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

export default MyFunctionalComponent;
Class Component

Here’s how to use the withSafeAreaInsets higher-order component (HOC) in a class component:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { withSafeAreaInsets, SafeAreaInsetsContext } from 'react-native-safe-area-context';

interface Props {
  insets: SafeAreaInsetsContext;
}

class MyClassComponent extends React.Component<Props> {
  render() {
    const { insets } = this.props;

    return (
      <View
        style={{
          ...styles.container,
          paddingTop: insets?.top,
          paddingBottom: insets?.bottom,
          paddingLeft: insets?.left,
          paddingRight: insets?.right,
        }}
      >
        <Text>Hello, world!</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
});

export default withSafeAreaInsets(MyClassComponent);

That’s it! You can also decide which sides (top, bottom, left and right) you want to apply padding to based on the design of your screen. If you’re not sure, applying it to all sides and seeing how the screen looks is best.

Remarks

  • While react-native-safe-area-context exports a SafeAreaView component, our experience indicates that it can also lead to screen jumping issues. For a robust and future-proof solution, use the useSafeAreaInsets hook for functional components or the withSafeAreaInsets HOC for class components.
  • Passing initialWindowMetrics to SafeAreaProvider ensures accurate safe area insets on app startup, preventing layout jumps caused by delayed inset calculations.
  • SafeAreaView is likely to be deprecated soon. With the introduction of edge-to-edge layouts on Android 15 (API 35) and React Native 0.76, the community is shifting toward react-native-safe-area-context for cross-platform consistency.
  • react-native-safe-area-context natively supports safe area insets on both iOS and Android, making it the ideal choice compared to SafeAreaView from react-native.

The post Fix Screen Jumping Using SafeAreaView in React Native appeared first on TechOpt.

]]>
https://www.techopt.io/programming/fix-screen-jumping-safeareaview-react-native/feed 0