React-Native Flatlist's onViewableItemChanged error - react-native

I am trying to account for changes when the element in view changes.
I get the following
Invariant Violation: Changing onViewableItemsChanged on the fly is not supported
I have the following
<Animated.FlatList
viewabilityConfig={carouselViewabilityConfig}
onViewableItemsChanged={onViewableItemsChanged}
...//other properties
/>
and my functions are
const onViewableItemsChanged = ({
viewableItems,
}: {
viewableItems: Array<number>;
}) => {
const insightsById = savedInsights.byId;
console.log('byId:!', insightsById);
if (!viewableItems.length) {
return;
}
const visibleInsightId =
insightsById[viewableItems[Math.max(viewableItems.length - 2, 0)].index];
console.log(visibleInsightId);
Analytics.logViewItem({ insight_id: visibleInsightId });
// const visibleInsightIndex = insightsById.indexOf(visibleInsightId);
};
const carouselViewabilityConfig = {
waitForInteraction: false,
minimumViewTime: 100,
viewAreaCoveragePercentThreshold: 50,
};
I saw a method using refs but it didn't work, my function wouldn't run.
Any help would be appreciated. Thanks.

Related

The Route line is not showing in android by using FeatureCollection

I need your help in little bit query,
i'm trying to render the multiple polyline on a single map,it look like as it (IOS),
it perfectly fine work fine in IOS but not work in android, so my code Snippet it,
import MapboxGL from '#react-native-mapbox-gl/maps';
const MapbBoxDirection = ({shape}: any) => {
const sp = returnOption(shape);
const Poliline = React.useMemo(() => {
return (
<MapboxGL.Animated.ShapeSource
id="routeSource"
buffer={512}
tolerance={1}
lineMetrics={false}
clusterRadius={10}
shape={sp}>
<MapboxGL.Animated.LineLayer
id="routeFill"
style={{
lineColor: '#ff8109',
lineWidth: 10,
lineRoundLimit: 12,
lineCap: 'round',
lineOpacity: 1.84,
}}
/>
</MapboxGL.Animated.ShapeSource>
);
}, [shape, sp]);
return Poliline;
};
import {featureCollection, lineString as makeLineString} from '#turf/helpers';
///// Make Json
export const returnOption = (res): any => {
const feature = res.map((item: any, index: any) => {
if (item[`Route${index}`]?.length > 2) {
return makeLineString(item[`Route${index}`]);
}
});
const featureCollectiondata = featureCollection(feature);
return featureCollectiondata;
};
it's work fine in IOS but not work in android,
i'm also trying to make a json manually without truf helper, i'm facing same problem.
So would you please help me How i can resolve it for android,
one more thing is SINGLE route work fine for both platform so when i'm trying to use featurecollection json it create problem,
Please I'm very Thankful to you,
After a lot a effort i got the Solution Sometime undefined and null is generate default Therefor route line not render on android, but ios it will handle it by default So
export const returnOption = async (res: any, setShape: any) => {
const feature = await Promise.all(
res.map(async (item: any, index: any): Promise<any> => {
if (item[`Route${index}`]?.length > 1) {
// return makeLineString(item[`Route${index}`]);
return {
type: 'Feature',
properties: {
prop0: 'value0',
prop1: 0.0,
},
geometry: {
type: 'LineString',
coordinates: item[`Route${index}`],
},
};
}
}),
);
const RemoveUndefined = feature?.filter(item => item !== undefined);
setShape({
type: 'FeatureCollection',
features: RemoveUndefined,
});
};
finally I have achieve the solution.

How to use diffClamp in reanimated 2?

I am trying to hide and show the header based on the scroll event from reanimated 2 useAnimatedScrollHandler and I need to use the diffClamp so whenever the user scrolls up the header should be shown in less time than the whole scroll event contentOffset.y value but the problem is diffClamp is I think from reanimated v1 and I need to use useAnimatedStyle hook in order to animate styles in reanimated v2 and finally it gives an error.
Can someone please help with it?
const clamp = (value, lowerBound, upperBound) => {
"worklet";
return Math.min(Math.max(lowerBound, value), upperBound);
};
const scrollClamp = useSharedValue(0);
const scrollHandler = useAnimatedScrollHandler({
onScroll: (event, ctx) => {
const diff = event.contentOffset.y - ctx.prevY;
scrollClamp.value = clamp(scrollClamp.value + diff, 0, 200);
},
onBeginDrag: (event, ctx) => {
ctx.prevY = event.contentOffset.y;
}
});
const RStyle = useAnimatedStyle(() => {
const interpolateY = interpolate(
scrollClamp.value,
[0, 200],
[0, -200],
Extrapolate.CLAMP
)
return {
transform: [
{ translateY: interpolateY }
]
}
})

When state changes for graphql variable, result stays the same on react-native

I'm trying to create an app using shopify graphql api to create an ecommerce app on react native expo.
I have an onPress that calls a setState to change the state of the graphQL variable but the results don't change from the initial state of 'currentSubCategories'
const [currentSubCategories, setSubCategories] = useState(Categories[0].subCategory[0].handle);
let {
collection,
loading,
hasMore,
refetch,
isFetchingMore,
} = useCollectionQuery(currentSubCategories, first, priceRange);
const [currentCategory, setCategory] = useState({categories: Categories[0]});
const onSubCategorySelect = (subCategory) => { setSubCategories(subCategory.handle) }
onPress={() => onSubCategorySelect(item)}
function useCollectionQuery(
collectionHandle: string,
first: number,
priceRange: [number, number],
) {
let [isInitFetching, setInitFetching] = useState<boolean>(true);
let [isReloading, setIsReloading] = useState<boolean>(true);
let [collection, setCollection] = useState<Array<Product>>([]);
let isFetchingMore = useRef<boolean>(false);
let hasMore = useRef<boolean>(true);
let defaultCurrency = useDefaultCurrency().data;
let { data, loading, refetch: refetchQuery } = useQuery<
GetCollection,
GetCollectionVariables
>(GET_COLLECTION, {
variables: {
collectionHandle,
first,
sortKey: ProductCollectionSortKeys.BEST_SELLING,
presentmentCurrencies: [defaultCurrency],
},
notifyOnNetworkStatusChange: true,
fetchPolicy: 'no-cache',
});
let getMoreUntilTarget = async (
targetAmount: number,
cursor: string | null,
handle: string,
filter: [number, number],
) => {
let result: Array<Product> = [];
let moreData: Array<Product> = [];
let { data } = await refetchQuery({
first,
collectionHandle: handle,
after: cursor,
});
...
useEffect(() => {
if (!loading) {
isFetchingMore.current = false;
}
if (isInitFetching && !!data && !!data.collectionByHandle) {
let newCollection = mapToProducts(data.collectionByHandle.products);
hasMore.current = !!data.collectionByHandle?.products.pageInfo
.hasNextPage;
setCollection(newCollection);
setIsReloading(false);
setInitFetching(false);
}
}, [loading, isInitFetching]); // eslint-disable-line react-hooks/exhaustive-deps
return {
collection,
loading: isReloading,
hasMore: hasMore.current,
isFetchingMore: isFetchingMore.current,
refetch,
};
}
I'm using flatList to show the result
<FlatList
data={collection}
renderItem={({ item }) => (
<Text>{item.title}</Text>
)}
/>
According to docs you have to pass new variables to refetch otherwise refetch will use initial values.
In this case (custom hook) you have 2 ways to solvethis problem:
return variables from your custom hook (taken from useQuery),
return some own refetch function.
1st option needs 'manual' variables updating like:
refetch( { ...variablesFromHook, collectionHandle: currentSubCategories } );
In 2nd case you can create myRefetch (and return as refetch) taking collectionHandle parameter to call refetch with updated variables - hiding 'complexity' inside your hook.
Both cases needs refetch call after updating state (setSubCategories) so you should use this refetch inside useEffect with [currentSubCategories] dependency ... or simply don't use state, call refetch directly from event handler (in onSubCategorySelect).

fireEvent on SegmentedControlIOS

I am using react-native-testing-library - https://callstack.github.io/react-native-testing-library/docs/getting-started
I have a <SegmentedControlIOS> - https://facebook.github.io/react-native/docs/segmentedcontrolios
I want to pres the first segment. I am doing this:
const testID = "SegmentedControl";
const stub = jest.fn();
const values = [{ label: "foo" }];
const { getByTestId } = render(
<SegmentedControlIOS values={['foo', 'bar']} onChange={stub} testID={testID} />
);
expect(() => {
getByTestId(testID);
}).not.toThrow();
fireEvent(getByTestId(testID), "change ", {
nativeEvent: {
value: values[0],
selectedSegmentIndex: 0,
},
});
However I get the error:
No handler function found for event: "change "
Screenshot below. Anyone know how to press different segments in <SegmentedControlIOS>?
fireEvent(element: ReactTestInstance, eventName: string, ...data:
Array): void
The change function is located in the fireEvent object. Here's how to use it:
Version 5 or later:
fireEvent.change(getByTestId(testID), { target: { value: values[0],selectedSegmentIndex: 0 } });
Version 5 or before:
const input = getByTestId(testID);
input.value = values[0];
input.selectedSegmentIndex = 0;
fireEvent.change(input);
If you want to check the onChange function of SegmentedControlIOS,
using fireEvent with native events that aren't already aliased by the fireEvent api.
// you can omit the `on` prefix
fireEvent(getByTestId(testID), 'onChange');
A solution was posted here, I didn't try it yet, but it looks more right I think - https://github.com/callstack/react-native-testing-library/issues/220#issuecomment-541067962
import React from "react";
import { SegmentedControlIOS } from "react-native";
import { fireEvent, render } from "react-native-testing-library";
const testID = "SegmentedControl";
const stub = jest.fn();
const values = [{ label: "foo" }];
const { getByTestId } = render(
<SegmentedControlIOS
values={["foo", "bar"]}
onChange={stub}
testID={testID}
/>,
);
it("sends events", () => {
fireEvent(getByTestId(testID), "onChange", {
nativeEvent: {
value: values[0],
selectedSegmentIndex: 0,
},
});
});

Save Sketched lines in LocalStorage

Sorry im posting this here
I want to save the info of each line i drew on canvas(the save action would be called onChange)
so i can retrieve this data and draw it on canvas again in case the user change screen or something.
I'm using expo-pixi to draw a image and sketch over it
onChangeAsync = async (param) => {
// here i want on change code i get the line informantion and store it
}
onLayout = async ({
nativeEvent: {
layout: { width, height },
},
}) => {
this.setState({
layoutWidth: width,
layoutHeight: height,
})
this.onReady();
}
onReady = async () => {
const { layoutWidth, layoutHeight, points } = this.state;
this.sketch.graphics = new PIXI.Graphics();
if (this.sketch.stage) {
if (layoutWidth && layoutHeight) {
const background = await PIXI.Sprite.fromExpoAsync(this.props.image);
background.width = layoutWidth * scaleR;
background.height = layoutHeight * scaleR;
this.sketch.stage.addChild(background);
this.sketch.renderer._update();
}
}
};
// The sketch component is pretty much as the example which comes with the lib
<Sketch
ref={ref => (this.sketch = ref)}
style={styles.sketch}
strokeColor={this.state.strokeColor}
strokeWidth={this.state.strokeWidth}
strokeAlpha={1}
onChange={this.onChangeAsync}
onReady={this.onReady}
/>
Does anyone have any clue? im kind of desperate
Thanks