React-native-ui-kitten: How to do custom component mapping using a functional component.

Created on 25 Jun 2020  路  3Comments  路  Source: akveo/react-native-ui-kitten

馃挰 Question

In the documentation it says that the styled decorator can be used on class components, but what if we don't want to write out an actual class component such as

@style('BrandButton')
export class BrandButton extends React.PureComponent<any>{}

and instead we wanted to use functional components that will inherit the styles

export const BrandButton = (props:any) => {}

or is this what the withStyles function was intended for. Although this function only seems to grab variables from the theme and doesn't do any custom component mapping itself.

UI Kitten and Eva version

| Package | Version |
| ----------- | ----------- |
| @eva-design/eva | 2.0.0|
| @ui-kitten/components |5.0.0|

Help wanted

Most helpful comment

I am in the midts of updating to 5. but since I am using mostly FCs the masking of styled HOC in a decorator doesn't work in my case. Therefore I am trying a hook alternative.

@3kumar Here are some thoughts on your hook. You should try to not return new values each time the hook is executed (i.e. on every render). This could have significant performance impact. My first approach would be to memo basically everything.

This is my version of your hook.

export function useStyled(name: string, sourceProps: Record<string, any>) {
  const [interaction, setInteraction] = React.useState([]);
  const mappingStyle = useContext(MappingContext);
  const evaTheme = useContext(ThemeContext);

  const service = useMemo(() => new StyleConsumerService(name, mappingStyle), [name, mappingStyle]);
  const defaultProps = useMemo(() => service.createDefaultProps(), [service]);

  const computedProps = useMemo(() => ({ ...defaultProps, ...sourceProps }), [defaultProps, sourceProps]);
  const computedStyle = useMemo(() => service?.createStyleProp(computedProps, mappingStyle, evaTheme, interaction), [
    service,
    computedProps,
    mappingStyle,
    evaTheme,
    interaction
  ]);
  return useMemo(
    () => ({
      ...computedProps,
      eva: {
        theme: evaTheme,
        style: computedStyle,
        dispatch: (newInteraction: any) => setInteraction(newInteraction)
      }
    }),
    [computedProps, evaTheme, computedStyle]
  );
}

All 3 comments

and instead we wanted to use functional components

No way to use it with styled function yet. And no way to use same API in future for functional components. I guess we need same thing implemented as hook.

this function only seems to grab variables from the theme

That's what the docs say

Any update on if the hook will be available soon, or we need to implement it ourselves?

UPDATE

I quickly tried a solution and came up with a solution. It works, though I am not sure if this is an optimal way of using a hook.

import { MappingContext } from '@ui-kitten/components/theme/mapping/mappingContext';
import { StyleConsumerService } from '@ui-kitten/components/theme/style/styleConsumer.service';
import { ThemeContext } from '@ui-kitten/components/theme/theme/themeContext';
import React from 'react';

export const useEvaStyled = (
  name: string,
  sourceProps: Record<string, any>,
) => {
  const [interaction, setInteraction] = React.useState([]);
  const mappingStyle = React.useContext(MappingContext);
  const evaTheme = React.useContext(ThemeContext);

  const service = new StyleConsumerService(name, mappingStyle);
  const defaultProps = service.createDefaultProps();

  const computedProps = { ...defaultProps, ...sourceProps };
  const computedStyle = service?.createStyleProp(
    computedProps,
    mappingStyle,
    evaTheme,
    interaction,
  );
  return {
    ...computedProps,
    eva: {
      theme: evaTheme,
      style: computedStyle,
      dispatch: (newInteraction: any) => setInteraction(newInteraction),
    },
  };
};

use it as follows:

import React from 'react';
import { TouchableOpacity } from 'react-native';
import { useEvaStyled } from '../hooks/useEvaStyled'; // change the path 

interface CircleButtonProps {}

export const CircleButton: React.FC<CircleButtonProps> = (props) => {
  const { eva, ...otherProps } = useEvaStyled('CircleButton', props);
  return <TouchableOpacity {...otherProps} style={eva.style} />;
};


I am in the midts of updating to 5. but since I am using mostly FCs the masking of styled HOC in a decorator doesn't work in my case. Therefore I am trying a hook alternative.

@3kumar Here are some thoughts on your hook. You should try to not return new values each time the hook is executed (i.e. on every render). This could have significant performance impact. My first approach would be to memo basically everything.

This is my version of your hook.

export function useStyled(name: string, sourceProps: Record<string, any>) {
  const [interaction, setInteraction] = React.useState([]);
  const mappingStyle = useContext(MappingContext);
  const evaTheme = useContext(ThemeContext);

  const service = useMemo(() => new StyleConsumerService(name, mappingStyle), [name, mappingStyle]);
  const defaultProps = useMemo(() => service.createDefaultProps(), [service]);

  const computedProps = useMemo(() => ({ ...defaultProps, ...sourceProps }), [defaultProps, sourceProps]);
  const computedStyle = useMemo(() => service?.createStyleProp(computedProps, mappingStyle, evaTheme, interaction), [
    service,
    computedProps,
    mappingStyle,
    evaTheme,
    interaction
  ]);
  return useMemo(
    () => ({
      ...computedProps,
      eva: {
        theme: evaTheme,
        style: computedStyle,
        dispatch: (newInteraction: any) => setInteraction(newInteraction)
      }
    }),
    [computedProps, evaTheme, computedStyle]
  );
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Gitldx picture Gitldx  路  3Comments

domsterthebot picture domsterthebot  路  3Comments

ugurozturk picture ugurozturk  路  4Comments

chamatt picture chamatt  路  3Comments

betodasilva picture betodasilva  路  3Comments