Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@volvo-cars/react-descendants

Package Overview
Dependencies
Maintainers
8
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@volvo-cars/react-descendants

A React hook that helps keep track of the indices of descendant components

  • 0.5.3
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
8
Created
Source

React Descendants

Questions? Ask in Slack #vcc-ui

@volvo-cars/react-descendants

A React hook that helps keep track of the indices of descendant components. It's useful for places where the exact rendering order of a descendent component is unknown. It allows each descendant component to know its index relative other components or renders of this specific component.

This way we can use component composition any way we like while knowing the exact index of each component:

<View>
  /*index 0*/
  <AccordionComp>1</AccordionComp>
  /*index 1*/
  <AccordionComp>2</AccordionComp>
  <Block>
    /*index 2*/
    <AccordionComp>3</AccordionComp>
  </Block>
  <Block>
    <Block>
      /*index 3*/
      <AccordionComp>4</AccordionComp>
    </Block>
  </Block>
</View>

Installation

💡 This package includes Typescript definitions

Usage

We first need to wrap the components which we want to know the rendering index for with a DescendantsIndexProvider and consume the index with useDescendantIndex. The hook will return a ref that needs to be passed to the react element to keep track off.

Simple

const { useDescendantIndex, DescendantsIndexProvider } =
  createDescendantsIndexContext();

const Component = () => {
  const { ref, index } = useDescendantIndex();
  return (
    <Block ref={ref}>
      <Text>Index:{index}</Text>
    </Block>
  );
};

const Wrapper = () => {
  return (
    <DescendantsIndexProvider>
      <Component />
      <View>
        <Component />
      </View>
      <Spacer />
      <View>
        <View>
          <Component />
        </View>
      </View>
    </DescendantsIndexProvider>
  );
};
render(<Wrapper />);

Advanced

Example below shows how the component indices update with mounting and unmounting of components. Try clicking on each component.

const { useDescendantIndex, DescendantsIndexProvider } =
  createDescendantsIndexContext();

const Component = ({ onClick, children }) => {
  const { ref, index } = useDescendantIndex();
  return (
    <Block ref={ref} onClick={onClick}>
      <Text>
        Component {children} | index:{index}
      </Text>
    </Block>
  );
};

const Wrapper = () => {
  const [hidden, setHidden] = React.useState([]);
  return (
    <DescendantsIndexProvider>
      {hidden.length ? (
        <Link onClick={() => setHidden([])}>Show all</Link>
      ) : null}
      {hidden.includes(1) ? null : (
        <Component onClick={() => setHidden([...hidden, 1])}>1</Component>
      )}
      <View>
        {hidden.includes(2) ? null : (
          <Component onClick={() => setHidden([...hidden, 2])}>2</Component>
        )}
      </View>
      <Spacer />
      <View>
        <View>
          {hidden.includes(3) ? null : (
            <Component onClick={() => setHidden([...hidden, 3])}>3</Component>
          )}
        </View>
      </View>
      <View>
        <View>
          {hidden.includes(4) ? null : (
            <Component onClick={() => setHidden([...hidden, 4])}>4</Component>
          )}
        </View>
      </View>
      <View>
        <View>
          {hidden.includes(5) ? null : (
            <Component onClick={() => setHidden([...hidden, 5])}>5</Component>
          )}
        </View>
      </View>
    </DescendantsIndexProvider>
  );
};
render(<Wrapper />);

Nested Providers

It's also possible to nest providers however we like, each hook will update its corresponding context value without affecting other contexts.

const { useDescendantIndex, DescendantsIndexProvider } =
  createDescendantsIndexContext();
const {
  useDescendantIndex: useDescendantIndexAccordionComp,
  DescendantsIndexProvider: DescendantsIndexProviderAccordionComp,
} = createDescendantsIndexContext();

const Component = ({ onClick, children }) => {
  const { ref, index } = useDescendantIndex();
  return (
    <Block ref={ref} onClick={onClick}>
      <Text>
        Component {children} | index:{index}
      </Text>
    </Block>
  );
};
const AccordionComp = ({ onClick, children }) => {
  const { ref, index } = useDescendantIndexAccordionComp();
  return (
    <Block ref={ref} onClick={onClick}>
      <Text>
        AccordionComp {children} | index:{index}
      </Text>
    </Block>
  );
};

const Wrapper = () => {
  const [hidden, setHidden] = React.useState([]);
  const [hiddenAccordionComp, setHiddenAccordionComp] = React.useState([]);
  return (
    <DescendantsIndexProvider>
      {hidden.length ? (
        <Link
          onClick={() => {
            setHidden([]);
            setHiddenAccordionComp([]);
          }}
        >
          Show all
        </Link>
      ) : null}
      {hidden.includes(1) ? null : (
        <Component onClick={() => setHidden([...hidden, 1])}>1</Component>
      )}
      <View>
        {hidden.includes(2) ? null : (
          <Component onClick={() => setHidden([...hidden, 2])}>2</Component>
        )}
      </View>
      <Spacer />
      <View>
        <View>
          {hidden.includes(3) ? null : (
            <Component onClick={() => setHidden([...hidden, 3])}>3</Component>
          )}
          <DescendantsIndexProviderAccordionComp>
            {hiddenAccordionComp.includes(1) ? null : (
              <AccordionComp
                onClick={() =>
                  setHiddenAccordionComp([...hiddenAccordionComp, 1])
                }
              >
                1
              </AccordionComp>
            )}
            <View>
              {hiddenAccordionComp.includes(2) ? null : (
                <AccordionComp
                  onClick={() =>
                    setHiddenAccordionComp([...hiddenAccordionComp, 2])
                  }
                >
                  2
                </AccordionComp>
              )}
              <View>
                {hidden.includes(4) ? null : (
                  <Component onClick={() => setHidden([...hidden, 4])}>
                    4
                  </Component>
                )}
              </View>
            </View>
          </DescendantsIndexProviderAccordionComp>
        </View>
      </View>
      <View>
        <View>
          {hidden.includes(5) ? null : (
            <Component onClick={() => setHidden([...hidden, 5])}>5</Component>
          )}
        </View>
      </View>
    </DescendantsIndexProvider>
  );
};
render(<Wrapper />);

FAQs

Package last updated on 10 May 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc