@fluentui-react-native/use-styling

中文文档
0.16.7发布于 2026/11/12MITTypeScriptES Module近 30 天下载 4127

Opinionated use styling hook implementation

原始使用文档
文档目录10 节
  1. Quick Reference
  2. Tokens
  3. Example
  4. Layering
  5. Caching
  6. States
  7. Tokens and Props
  8. Slot Props
  9. Direct Objects
  10. Functions

@fluentui-react-native/use-styling

This package provides a framework for building a hook function which produces opinionated styles, for both simple and higher order components. This is built with the following principles in mind:

  • Theming - the useStyling hook allows for styles to be built from information contained in a theme object. This package is not opinionated about the shape of the theming system, it is injected when building the hook.
  • Caching - props and styles should not be calculated more often than necessary. Results will be cached both to improve performance, and to maintain consistent object references for style objects.
  • Reuse - the system should be designed to ensure caching uses as few keys as necessary and that generated styles be shared as much as is possible. This is important in situations like generating class names for the styles.

An extremely simple example might look like:

// create the styling hook which can be used in the component, note that this gets created once and
// should not be done inside the component itself
const useSyling = buildUseStyling(myComponentOptions, themeHelper);

// component implementation, consuming the styling hook
const MyComponent = (props) => {
  // get some default/styled props for the container and content child components
  const { container, content } = useStyling(props);
  // render as normal but mixin those values to pass the props to the sub-components
  const { textValue, ...rest } = props;
  const merged = { ...container, ...rest };
  return (
    <View {...merged}>
      <Text {...content}>{textValue}</Text>
    </View>
  );
};

Now this example isn't particularly useful but demonstrates the basic role that the styling hook can play in a HOC.

Quick Reference

At the core of this system is the idea that: Tokens + Theme ==> Styles. This can be thought of as:

  • Your styles are produced via a recipe, defined as a function in slotProps
  • The tokens are the ingredients for your recipe
  • Some of those tokens come from constants
  • Some of those tokens come from the theme
  • Some tokens could even come from props but this is not the default and needs to be declared in tokensThatAreAlsoProps

The overall signature of the method is as follows:

const useStyling = buildUseStyling(
  /* options that define the component */
  {
    /* Step 1: Build up a single Tokens object with constants for the component */
    tokens?: [
      /* object */
      { },
      /* theme function */
      (theme: Theme) => ({ /* created object */ }),
      /* name to lookup */
      'NameToLookup'
    ],

    /* Step 2: Potentially apply states (if applicable) to the Tokens */
    states?: ['hovered', 'pressed', 'disabled'],

    /* Step 3: Copy some/none/all props to Tokens */
    tokensThatAreAlsoProps?: 'all' /* all props are tokens */
              | 'none' | undefined /* no props are tokens */
              | ['token1', 'token2'] /* list of tokens which also appear in props */,

    /* Step 4: Create props for child components from Tokens and Theme */
    slotProps?: {
      /* props as a constant object */
      slot1: { },
      /* props as a function of tokens and theme, with smart caching/filtering */
      slot2: buildProps((tokens: Tokens, theme: Theme) => {
        // function to generate props
        return { style: { color: tokens.token1 }}
      }, ['token1'])
      /* props as a custom function of tokens, theme, cache */
      slot3: (tokens: Tokens, theme: Theme, cache: GetMemoValue) => {
        // function to generate props
      }
    }
  },
  /* theme helper plugin, global per theming system */
  {
    /* get the active theme, usually from the context */
    useTheme: () => { return useContext(ThemeProvider) || getDefaultTheme() };

    /* lookup a component in the theme to see if token overrides are available */
    getComponentInfo: (theme: Theme, name: string) => lookupComponentInTheme(theme, name);)
  }
);

Tokens

A token is simply a setting that informs the styling of the component. These can be thought of as an additional set of component props that are automatically built-up by the framework. Typically these are set at component creation time or overriden by a theme but can can come from a variety of sources:

  • Objects - this is a set of values contained within an object. These values are assumed to be unchanging over the lifetime of the object.
  • Theme Functions - this allows values to be set in relation to values in a theme. An example would be a color being set to a particular entry in a color palette in the theme.
  • Name Lookup - this will query the theme for a token object or theme function for this component.

Example

/** Tokens interface for this component */
interface Tokens {
  backgroundColor?: ColorValue;
  borderWidth?: number;
  borderRadius?: AnimatableNumericValue | string;
}

/** Build the styling hook */
const useStyling = buildUseStyling({
  tokens: [
    /* fixed object */
    {
      borderWidth: 1,
      borderRadius: 2,
    },
    /* theme function */
    (theme: Theme) => {
      backgroundColor: theme.palette.bodyBackground || 'white';
    },
    /* name lookup */
    'MyComponentName',
  ],
  ...otherSettings,
});

Layering

These tokens will be deeply merged in the order they appear in the array.

const mergedTokens = merge(
  ...options.tokens.map(entry => {
    // string gets converted to object or function (or empty object)
    if (typeof entry === 'string') {
      entry = themeHelper.getComponentInfo(entry) || {};
    }
    // return either the function call (which will produce an object) or the object
    return typeof entry === 'function' ? entry(theme) : entry;
  });
);

Caching

The only variable input to this entire process is the theme. As a result the result of all of this will be cached based on:

  • useStyling closure, each closure will have its own unique cached values
  • theme object reference, stored in a WeakMap

As a result this calculation will run one time per theme, per component type.

States

Some components may have additional states or modes that can be applied to them. As an example a Button component might have a state called hovered or pressed. In this case the Tokens interface should be as follows:

interface ButtonTokens {
  // base values
  backgroundColor?: ColorValue;
  color?: ColorValue;
  borderColor?: ColorValue;

  // states
  hovered?: ButtonTokens;
  pressed?: ButtonTokens;
}

In this case the states option should be provided as follows:

const useStyling = buildUseStyling({
  tokens: [/* token settings */],
  states: ['hovered', 'pressed'],
  ...otherSettings,
});

For each entry in the states array, in the order they appear, the following will happen:

  • Evaluate whether the state applies. This will be true if props[state] is truthy, or if a passed in closure evaluates as truthy. More about this below.
  • If the state is true, and tokens contains a sub-object matching that name, the sub-object will be merged into the parent object.

The generated useStyling hook has an optional second parameter which is a function of the form:

type HasLayer = (state: string) => boolean;

This allows states to be set based on states in addition to props. An example might look like:

interface ButtonState {
  hovered?: boolean;
  pressed?: boolean;
}

const Button = (props: ButtonProps) => {
  // get some state value that figures out whether the button is pressed and/or hovered
  const buttonState: ButtonState = useButtonState(props);
  // get styling values based on props and the current state
  const { container, icon, label } = useStyling(props, (stateName) => buttonState[stateName]);

  const buttonProps = useButtonMagic(props, container);
  return (
    <View {...buttonProps}>
      <Image {...icon} source={props.iconSrc} />
      <Text {...label}>{props.text}</Text>
    </View>
  );
};

Tokens and Props

The ideal scenario from a caching perspective, is for tokens and props to be completely separate. This keeps variability very low and reduces the need for frequent style recalculations. From the perspective of someone using the components this sharply limits flexibility. As a result it may be useful for some tokens to be surfaced as props on the component.

Because props are not provided to the final stage of the useStyling workflow, if any props are also tokens, they need to be declared so that they can override the token values coming from the theme or constants. This is done via the tokensThatAreAlsoProps property. This has three behaviors:

ValueBehavior
'none' or undefinedNo properties are tokens and tokens will be left as is.
'all'All properties should be considered tokens. This equates to: tokens = { ...tokens, ...props }
(keyof Tokens)[]Provides a discrete list of values to copy from props to tokens (if present)

Slot Props

Part of the challenge of building a higher order component, particularly one that is customizeable, is figuring out how to map a single set of props into a multiple internal components. While it is standard to expose a style on the props interface of a component, this can only map to one of the internal components.

Customizing HOCs by directly targeting the styles of the sub-components is problematic in that it leaks the implementation details. As a result, it becomes challenging to maintain or update the component long term without breaking customers.

The solution used by the useStyling module is to allow focus customization on the various Token values, then have a defined mapping of how those Tokens translate to props for each child component. In the parlance of this library, each child component is referred to as a slot.

Each slot returns its own props object, either directly or via a function.

Direct Objects

The simplest way to provide props for a slot is by providing an object directly. While limited in applicability, it looks as follows:

const useStyling = buildUseStyling({
  ...precedingOptions,
  slotProps: {
    slot1: { style: { display: 'flex' } },
  },
});

Functions

The functions are assumed to have the following signature:

function propBuilder(tokens: Tokens, theme: Theme, cache: GetMemoValue<Props>): Props;

While tokens and theme have been discussed at length above, the cache will be a cache instance keyed on:

  • The theme
  • The tokens coming from the theme
  • This slot

If there are no tokens which are also props, i.e. if tokensProps is falsy, this is sufficient and the function could be written as:

const slotFn = (tokens: Tokens, theme: Theme, cache: GetMemoValue<Props>) =>
  cache(
    () => {
      return {
        style: {
          backgroundColor: tokens.backgroundColor,
          // etc.
        },
      };
    },
    [/* no keys, just direct cache the function result*/],
  )[0];

If some all props are tokens then those keys should be considered in the caching. This would then turn into:

const slotFn = (tokens: Tokens, theme: Theme, cache: GetMemoValue<Props>) => {
  const { backgroundColor, color, borderRadius } = tokens;
  return cache(
    () => ({
      style: { backgroundColor, color, borderRadius },
    }),
    [backgroundColor, color, borderRadius],
  )[0];
};

buildProps helper

The library provides a helper called buildProps to make this more ergonomic. It provides an implementation for the full caching function above and would be used as follows:

const slotFn = buildProps(
  (tokens: Tokens, theme: Theme) => ({
    style: {
      backgroundColor: tokens.backgroundColor,
      color: tokens.color,
      borderRadius: tokens.borderRadius,
    },
  }),
  ['backgroundColor', 'color', 'borderRadius'],
);

The primary benefit this function provides is that buildUseStyling knows how to refine these lists when constructing the hooks. As a result the caching will adjust automatically based on what is specified in tokenProps.

版本与发布记录

@fluentui-react-native/use-styling 共发布 61 个版本,首次发布于 2020/07/29;过去 12 个月发布了 12 个版本。

版本发布日期距今
0.16.7latest2026/11/124 天前
0.16.62026/10/2918 天前
0.16.52026/09/241 个月前
0.16.42026/09/231 个月前
0.16.32026/09/022 个月前
0.16.22026/08/212 个月前

关于 @fluentui-react-native/use-styling 的常见问题

@fluentui-react-native/use-styling 是什么?

Opinionated use styling hook implementation

如何安装 @fluentui-react-native/use-styling?

在项目目录运行 npm install @fluentui-react-native/use-styling,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(18.2.0 || 19.0.0 || 19.1.4)、react-native(^0.73.0 || ^0.74.0 || ^0.78.0 || ^0.81.6)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@fluentui-react-native/use-styling 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@fluentui-react-native/use-styling 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@fluentui-react-native/use-styling 可以商用吗?

@fluentui-react-native/use-styling 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@fluentui-react-native/use-styling 的下载量有多少?

根据 npm 官方下载统计,@fluentui-react-native/use-styling 在 2026/10/15 – 2026/11/13 这 30 天内被下载 4,127 次,日均约 138 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@fluentui-react-native/use-styling 还在维护吗?

最新版本 0.16.7 发布于 2026/11/12(4 天前);至今共发布 61 个版本,其中过去 12 个月发布了 12 个;首次发布于 2020/07/29。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。