You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React(Expo)与React Native项目共享代码及创建共享库的最简方案咨询

Hey there! Awesome plan—sharing code between React web and React Native is a fantastic way to keep your brand consistent and avoid repeating work. Let’s walk through the simplest, most straightforward implementation that fits your exact project structure request.

Step 1: Set Up Your Project Structure

First, lay out your folders exactly as you described. This keeps everything organized and makes it easy to distinguish shared vs platform-specific code:

your-project/
├── web/                # Your React web app (use Create React App or Vite)
│   ├── src/
│   └── package.json
├── mobile/             # Your React Native app (Expo or React Native CLI works)
│   ├── src/
│   └── package.json
└── shared/             # All shared code lives here
    ├── components/
    │   └── Button/     # Shared Button component folder
    └── constants/      # Shared brand assets
Step 2: Create Shared Brand Constants

Put all your brand-specific values (like colors, font weights, or spacing) in the shared/constants folder. This ensures your brand stays consistent across both platforms without duplication.

Create shared/constants/brand.js:

export const BRAND_COLORS = {
  primary: "#2563eb",   // Your main brand blue
  secondary: "#10b981", // A complementary green
  error: "#ef4444",     // Error state red
  white: "#ffffff",
};

export const FONT_WEIGHTS = {
  regular: 400,
  bold: 700,
};
Step 3: Build the Shared Button Component

The key here is separating shared logic/props from platform-specific rendering. We’ll use React’s platform-specific file suffixes (.web.jsx and .native.jsx) to let each platform load its own button implementation, while keeping the core logic shared.

3.1 Shared Button Logic File

Create shared/components/Button/Button.jsx—this is the "shell" that handles shared props, logic, and passes data to the platform-specific button:

import { BRAND_COLORS } from "../../constants/brand";
// Dynamically import the platform-specific button (React/React Native auto-detects suffixes)
import ButtonImpl from "./Button.platform";

export default function Button({
  children,
  variant = "primary",
  onPress,
  ...rest
}) {
  // Shared logic: Get the correct brand color based on the variant
  const bgColor = BRAND_COLORS[variant];

  // Shared handler: Wrap onPress to add any cross-platform logic (e.g., loading states)
  const handlePress = () => {
    if (onPress) onPress();
  };

  // Pass shared values and props to the platform-specific button
  return (
    <ButtonImpl
      bgColor={bgColor}
      onPress={handlePress}
      {...rest}
    >
      {children}
    </ButtonImpl>
  );
}

3.2 Web-Specific Button Rendering

Create shared/components/Button/Button.web.jsx—this uses the standard HTML <button> element:

import { BRAND_COLORS, FONT_WEIGHTS } from "../../constants/brand";

export default function ButtonWeb({ bgColor, onPress, children, ...rest }) {
  return (
    <button
      style={{
        backgroundColor: bgColor,
        color: BRAND_COLORS.white,
        padding: "10px 20px",
        border: "none",
        borderRadius: "6px",
        cursor: "pointer",
        fontSize: "16px",
        fontWeight: FONT_WEIGHTS.bold,
      }}
      onClick={onPress}
      {...rest}
    >
      {children}
    </button>
  );
}

3.3 Native-Specific Button Rendering

Create shared/components/Button/Button.native.jsx—this uses React Native’s TouchableOpacity (the standard native button component):

import { TouchableOpacity, Text, StyleSheet } from "react-native";
import { BRAND_COLORS, FONT_WEIGHTS } from "../../constants/brand";

export default function ButtonNative({ bgColor, onPress, children, ...rest }) {
  return (
    <TouchableOpacity
      style={[styles.button, { backgroundColor: bgColor }]}
      onPress={onPress}
      {...rest}
    >
      <Text style={styles.text}>{children}</Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  button: {
    paddingVertical: 10,
    paddingHorizontal: 20,
    borderRadius: 6,
  },
  text: {
    color: BRAND_COLORS.white,
    fontSize: 16,
    fontWeight: FONT_WEIGHTS.bold,
    textAlign: "center",
  },
});
Step 4: Use the Shared Component in Web & Mobile

To make importing easy, add the shared folder as a local dependency in both your web and mobile projects:

  1. In web/package.json, add:
    "dependencies": {
      // ... your existing web dependencies
      "shared": "file:../shared"
    }
    
  2. In mobile/package.json, add the same line.

Now you can import the shared Button component in either project like this:

Web Example (web/src/App.jsx)

import Button from "shared/components/Button/Button";

function App() {
  return (
    <div style={{ padding: "2rem" }}>
      <Button variant="primary" onPress={() => alert("Web primary button clicked!")}>
        Web Primary Button
      </Button>
      <Button variant="secondary" onPress={() => alert("Web secondary button clicked!")} style={{ marginTop: "1rem" }}>
        Web Secondary Button
      </Button>
    </div>
  );
}

export default App;

Native Example (mobile/App.jsx)

import { View, StyleSheet } from "react-native";
import Button from "shared/components/Button/Button";

export default function App() {
  return (
    <View style={styles.container}>
      <Button variant="primary" onPress={() => alert("Native primary button clicked!")}>
        Native Primary Button
      </Button>
      <Button variant="secondary" onPress={() => alert("Native secondary button clicked!")} style={{ marginTop: 16 }}>
        Native Secondary Button
      </Button>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
    padding: 20,
  },
});
Quick Tips for Smooth Sharing
  • Keep shared code platform-agnostic: Only put logic, constants, or component shells in shared—avoid anything that relies on web APIs (like window) or native APIs (like Alert directly) unless you wrap them in platform-specific modules.
  • Expo users win: Expo automatically detects .web.jsx and .native.jsx suffixes, so no extra config is needed. For React Native CLI, you might need to tweak your Babel config to handle platform files.
  • Add TypeScript (optional but helpful): If you use TypeScript, you can define shared prop types in the shared folder to ensure consistency across platforms.

内容的提问来源于stack exchange,提问作者Vishal Avalani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:50:09