question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Creating sharedValue inside an hook

See original GitHub issue

Description

I’m creating an Animated list so that I can do

type ItemType = {
    id: string
    color: string
}

const Screen > = function ({}) {

	const [items, setItems] = useState<ItemType[]>([])
	
	...

	return (
	 <DraggableList
	     data={items}
	     renderItem={_renderItem}
	  />
	)
}

In DraggableList I want to maintain an up-to-date Map containing shared values like offset. What I would do normally is using useEffect inside DraggableList so that I have something like

const myMap = useRef(new Map()).current

useEffect(() => {
   data.map((x) => {
     if(!myMap.has(x.id))
        myMap.set(x.id, { offset: useSharedValue(0)})
   })
}, [data])

and some logic to handle delete / add of new items.

However, as expected, I cannot use useSharedValue inside useEffect. How can I create sharedValues like I could do in V1 with new Animated.Value ?

Package versions

  • React: 16.13.1
  • React Native: 0.63.2
  • React Native Reanimated: 2.0.0-alpha.7

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
Andariuscommented, Oct 6, 2020

Ok I think I got it 😃 Thanks !

For reference:


type DragListContextProps = {
    items: Map<Item['id'], AnimatedItem>
    updateItems: (itemId: Item['id'], item: AnimatedItem) => void
}
const DragListContext = React.createContext<DragListContextProps>({
    items: new Map(),
    updateItems: () => {}
})

const CardItem: FC<{
    style: StyleProp<ViewStyle>
    id: Item['id']
}> = function ({ style, id }) {
    const offset = useSharedValue(0)

    const { items, updateItems } = useContext(DragListContext)

    useEffect(() => {
        if (!items.has(id)) updateItems(id, { offset })
    }, [items])

    function onPress() {
        console.log('Pressing : ', items.size)
    }

    const onGestureEvent = useAnimatedGestureHandler(
        {
            onStart: (_, ctx) => {},
            onActive: (event, ctx) => {
                console.log('active: ', items.size)
            },
            onEnd: (event) => {}
        },
        [items]
    )

    return (
        <PanGestureHandler {...{ onGestureEvent }}>
            <Animated.View>
                <RectButton onPress={onPress}>
                    <Card style={style} />
                </RectButton>
            </Animated.View>
        </PanGestureHandler>
    )
}

const DynamicItemsScreen: RNNFC<Props> = function ({}) {
    const [items, setItems] = useState<Item[]>([])
    const [animItems, setAnimItems] = useState<Map<string, AnimatedItem>>(
        new Map()
    )

    function onPress() {
        setItems((old) => [
            ...old,
            {
                id: 'item-' + old.length,
                color: colors[Math.floor(Math.random() * colors.length)]
            }
        ])
    }

    function updateItems(itemId: Item['id'], item: AnimatedItem){
        setAnimItems((old) => {
            const newMap = new Map([...old])
            newMap.set(itemId, item)
            return newMap
        })
    }

    return (
        <View style={styles.container}>
            <DragListContext.Provider value={{ items: animItems, updateItems}}>
                {items.map((x, i) => (
                    <CardItem
                        key={i}
                        id={x.id}
                        style={{ backgroundColor: x.color }}
                    />
                ))}
            </DragListContext.Provider>

            <View style={styles.btnsContainer}>
                <RectButton style={styles.btn} onPress={onPress}>
                    <Text style={styles.text}>Add Item</Text>
                </RectButton>
            </View>
        </View>
    )
}
1reaction
terrysahaidakcommented, Oct 5, 2020

Use context for this.

So you’ll need to wrap the list with a context, and the user should call useDraaggableListItem() where you useContext to grab all the data you need and do whatever logic you need.

It can be either in the user’s component or in your wrapper around the list item you render (where you handle measurements and onPress).

Read more comments on GitHub >

github_iconTop Results From Across the Web

useSharedValue | React Native Reanimated - Software Mansion
Use this hook to create a reference to a JavaScript value that can be shared with worklets. Shared Values serve a similar purpose...
Read more >
Building Your Own Hooks - React
Building your own Hooks lets you extract component logic into reusable functions. ... (such as setting up a subscription and remembering the current...
Read more >
How to use a custom-hook that returns a value, inside another ...
getUserInfro method, and then gets part of the returned object and sets a state variable with it. I also have another Hook called...
Read more >
Hacking React Hooks: Shared Global State
Larry, Curly, Moe, and Curly Jr all use the custom Hook useCounter() . They all display the value of count . And they...
Read more >
React Hooks cheat sheet: Best practices with examples
To help demonstrate how to solve common React Hooks questions, ... an initial state value, state could also be initialized from a function, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found