I’m trying to call the React useState setter function from within a worklet function. This callback is provided by the package – https://github.com/mgcrea/react-native-dnd which exposes an onDragEnd event.
I’ve found other SO answers suggesting to use runOnJS from react-native-reanimated in order to run JS code from within the UI thread (this worklet function). But console logs within runOnJS
and in the render function itself is not updated when the handleDragEnd
is emit.
What needs to change in order to call the useState setter within a worklet function?
Below is a snippet showing the worklet and some of the render function:
import {runOnJS} from 'react-native-reanimated';
const handleDragEnd: DndProviderProps['onDragEnd'] = ({active, over}) => {
'worklet';
if (over) {
console.log('onDragEnd', {active, over});
console.log(active);
// Create a new item based on the type of the dragged item
const newItem = {
partName: `${active.id.split('-')[0]}`,
};
runOnJS(() => {
// Add the new item to ductItems
setDuctItems((prevDuctItems) => {
const updatedDuctItems = [...prevDuctItems, newItem];
console.log('Updated ductItems:', updatedDuctItems);
return updatedDuctItems;
});
});
dynamicData.value = {
over: over,
};
}
};
return (
<GestureHandlerRootView>
<View style={styles.container}>
<DndProvider
onDragEnd={handleDragEnd}
>
<Droppable id="drop" style={styles.dropBox}>
<Text>DROP</Text>
</Droppable>
<View style={styles.partsContainer}>
<Text>{JSON.stringify(ductItems)}</Text>
{ductItems.map((item, index) => (
<DraggableCustomComponent
style={styles.partItem}
id={`${item.partName}-${index}-key`}
key={`${item.partName}-${index}-key`}
partType={item.partName}
data={dynamicData}
/>
))}
</View>
</DndProvider>
);
The issue was that I wasn’t invoking runOnJs correctly according to the reanimated docs. The function uses “currying” pattern which takes the args as last param:
const replaceDuctPart = (item: {partName: string}) => {
setDuctItems((prevDuctItems) => {
const updatedDuctItems = [...prevDuctItems, item];
console.log('Updated ductItems:', updatedDuctItems);
return updatedDuctItems;
});
};
runOnJS(replaceDuctPart)(newItem);