Я использую React Native Gesture Handler в js-файле, и когда я запускаю код, я получаю эту ошибку
ОШИБКА [реагировать-родной-жест-обработчик] Некоторые обратные вызовы в жесте являются рабочими программами, а некоторые нет. Либо убедитесь, что все обратные вызовы помечены как «рабочие», если вы хотите запускать их в потоке пользовательского интерфейса, либо используйте модификатор «.runOnJS(true)» в жесте явно, чтобы запускать все обратные вызовы в потоке JS.
КОД:
` импортировать * как React из 'реагировать'; импортировать {Просмотр, Текст, Размеры} из «реагировать на родной»; импортировать стили из «../styles/style_home» импортировать * как Animatable из 'реагировать-родной-анимируемый' импортируйте {Canvas, Path, Skia} из @shopify/react-native-skia; импортировать {curveBasis, line, ScaleLinear, ScalePoint} из 'd3'; импортировать DataPalmas из «../../assets/csvjson.json» импортировать градиент из './Gradient' импортировать XAxisText из './XAxisText'; импорт {зажим, runOnJS, useSharedValue, withDelay, withTiming} из 'реагировать-родной-реанимированный'; импортировать курсор из './Cursor' Импортировать { Жест, Детектор жестов, PanGestureHandlerEventPayload, } из 'реагировать-родной-жест-обработчик'; импортировать {getYForX, parse} из 'реагировать-native-redash';
export default function () {
const [showCursor, setShowCursor] = React.useState(false)
const animationLine = useSharedValue(0)
const animationGradient = useSharedValue({x: 0, y: 0})
const cx = useSharedValue(0)
const cy = useSharedValue(0)
React.useEffect(() => {
animationLine.value = withTiming(1, {duration:2000})
animationGradient.value = withDelay(2000, withTiming({x: 0, y: chartHeight}, {duration: 1000}))
}, [])
const chartHeight = 150
const chartWidth = Dimensions.get('window').width
const chartMargin = 20
const data = DataPalmas
const xDomain = data.map((dataPoint) => dataPoint.Data)
const xRange = [chartMargin, chartWidth - chartMargin]
const x = scalePoint().domain(xDomain).range(xRange).padding(0)
const stepX = x.step()
const max = Math.max(...data.map(val => val.Precipitacao))
const min = Math.min(...data.map(val => val.Precipitacao))
const yDomain = [min, max]
const yRange = [chartHeight, 0]
const y = scaleLinear().domain(yDomain).range(yRange)
const curvedLine = line()
.x(d => x(d.Data))
.y(d => y(d.Precipitacao))
.curve(curveBasis)(data)
const linePath = Skia.Path.MakeFromSVGString(curvedLine)
const path = parse(linePath.toSVGString())
function handleGestureEvent(e){
const clampValue = clamp(
Math.floor(e.absoluteX / stepX) * stepX + chartMargin,
chartMargin,
chartWidth - chartMargin,
)
cx.value = clampValue
cy.value = getYForX(path, Math.floor(clampValue))
}
const pan = Gesture.Pan()
.onTouchesDown(() => {
setShowCursor(true)
})
.onTouchesUp(() => {
setShowCursor(false)
})
.onBegin(handleGestureEvent)
.onChange(handleGestureEvent)
return (
<Animatable.View style = {styles.container__graphic} animation = {"fadeInLeft"}>
<GestureDetector gesture = {pan}>
<Canvas
style = {{
width: chartWidth,
height: chartHeight+30,
}}>
<Path
path = {linePath}
style = {'stroke'}
strokeWidth = {2}
color = {'#0bb861'}
strokeCap = {'round'}
start = {0}
end = {animationLine}/>
<Gradient
chartHeight = {chartHeight}
chartMargin = {chartMargin}
chartWidth = {chartWidth}
curvedLine = {curvedLine}
animationGradient = {animationGradient}
/>
{data.map((dataPoint, index) => (
<XAxisText
x = {x(dataPoint.Data)}
y = {chartHeight}
text = {dataPoint.Data}
key = {index}
/>
))}
{showCursor &&
<Cursor
cx = {cx}
cy = {cy}
chartHeight = {chartHeight}
/>}
</Canvas>
</GestureDetector>
</Animatable.View>
);
}`
Когда я использую «worklet» в этой функции, приложение вылетает, когда я нажимаю
function handleGestureEvent(e){
**'worklet'**
const clampValue = clamp(
Math.floor(e.absoluteX / stepX) * stepX + chartMargin,
chartMargin,
chartWidth - chartMargin,
)
cx.value = clampValue
cy.value = getYForX(path, Math.floor(clampValue))
}
Вам нужно добавить .runOnJS(true)
к вашему Gesture.Pan()
вызову, например:
const pan = Gesture.Pan()
.runOnJS(true)
.onTouchesDown(() => {
setShowCursor(true)
})
.onTouchesUp(() => {
setShowCursor(false)
})
.onBegin(handleGestureEvent)
.onChange(handleGestureEvent)
Плагин Babel от Reanimated автоматически обрабатывает обратные вызовы, когда обратные вызовы объединены в цепочку. Использование .runOnJS(true)
заставит каждый обратный вызов в цепочке выполняться в потоке js, что может отрицательно повлиять на производительность, если в цепочке есть обратный вызов с логикой анимации внутри, поэтому было бы более оптимально использовать функцию runOnJS
выборочно для функций, которые должны выполняться на JS. поток (например, установщики состояния).
Сбой при работе вручную handleGestureEvent
— это еще одна проблема, которая может быть внутренней ошибкой react-native-reanimated
(например, вот эта). Я бы попробовал обновить react-native-reanimated
до последней версии или переместить код handleGestureEvent
в обратные вызовы .onBegin
и .onChange
напрямую, используя автоматическую ворлетизацию, и пометить дублирующуюся логику с помощью FIXME (или, что еще лучше, создать заявку на технический долг) провести рефакторинг позже, когда ошибка будет обнаружена и исправлена.
const pan = Gesture.Pan()
.onTouchesDown(runOnJS(() => {
setShowCursor(true)
}))
.onTouchesUp(runOnJS(() => {
setShowCursor(false)
}))
.onBegin((e) => {
const clampValue = clamp(
Math.floor(e.absoluteX / stepX) * stepX + chartMargin,
chartMargin,
chartWidth - chartMargin,
)
cx.value = clampValue
cy.value = getYForX(path, Math.floor(clampValue))
})
.onChange((e) => {
const clampValue = clamp(
Math.floor(e.absoluteX / stepX) * stepX + chartMargin,
chartMargin,
chartWidth - chartMargin,
)
cx.value = clampValue
cy.value = getYForX(path, Math.floor(clampValue))
})