dynamically change style based on an argument using useAnimatedStyle - react-native

I have a list of blocks as childrens when a sequence those blocks are hovered, I want them to change there opacity, the function BlockStyle below does not change the style based on index, how can I change each child opacity based on it index
this is what i tried,
const opacity = useSharedValue(new Array(BlockNumber).fill(1));
const BlockStyle = (index) => useAnimatedStyle(() => {
return {
opacity : opacity.value[index]
};
})
opacity.value[block] = 0.5

Related

react-native-reanimated useDerivedValue does not modify the dom

I have the simplest example possible with useDerivedValue:
A SharedValue that is modified when scrolling.
A derived boolean value based on this scroll position
const isShown = useDerivedValue(() => {
console.log('y', currentPositionY.value);
return currentPositionY.value > 40;
}, [currentPositionY]);
The y is logged and modified as it should.
A component that should display a different text based on this boolean:
const TestC = ({ isShown }: { isShown: SharedValue<boolean> }) => {
console.log('isS', isShown.value);
if (isShown.value) {
return <Text>shown</Text>;
} else {
return <Text>not shown</Text>;
}
};
But the TestC component is not updated following the derived value.
What am I missing?

Is there a Vue way of creating a drag ghost image?

I need to create a custom ghost image for a dragged element. And also I need to change it's style a bit. This is my code:
const onDragStart = (e) => {
const ghost = e.target.cloneNode(true);
ghost.setAttribute("id", "ghost");
ghost.style.position = "absolute";
ghost.style.right = "-999px";
// counter is an element that should not be displayed on a ghost image
ghost.getElementsByClassName("counter")[0].remove();
document.body.appendChild(ghost);
e.dataTransfer.setDragImage(ghost, 20, 20);
};
const onDragEnd = () => {
const ghost = document.getElementById("ghost");
if (ghost) {
ghost.remove();
}
};
Since I use Vue, manipulating DOM directly seems like a bad idea. Is there any way to do the same result, but in a Vue-way?

Reset the initial state value in Recat Native

Requirement: I have to blink a View for 2 sec with 2 different color (for ex red and white).
I can do this by using this code -
const [state, setState] = React.useState(false)
const [initialState, setInitialState] = React.useState(0)
React.useEffect(() => {
if (initialState < 2){
let interval = setInterval(() => {
setState(true)
setInitialState(initialState + 1)
setTimeout(() => {
setState(false)
}, 80);
}, 300);
setTimeout(() => {
clearInterval(interval)
}, 600);
}
}, [initialState])
and called it like -
<View style={{...styles.mainContainer, backgroundColor: state ? Colors.GRO7 : Colors.GRC9}}>
Another Requirement: I have another screen from it i an change the address, on successful address change i have to blink this view again for 2 sec. I'm not sure where i can reset the initial value to 0 again.
I am new In react native, could some one guide me how to achieve this functionality
Can‘t completely understand what‘s your target.
Here is a blinking text sample
you can pass in the initial value to this component instead of defining 0 in this line:
const [initialState, setInitialState] = React.useState(0)
you could have a param to pass in and put it instead of 0 so that every time that param changes this component will re render. and so you get a new initial state.
for example:
const [initialState, setInitialState] = React.useState(initialValue)

Efficient way to scroll to certain index in FlatList with variable item size

I'm having a trouble adding scroll/jump to certain index functionality on FlatList in react-native. My FlatList items are vary in size (height) which makes me unable to implement getItemLayout since this requires me to have prior knowledge about the FlatList item size, therefore I cannot use scrollToIndex (which requires getItemLayout to be implemented).
My solution was to get each item's size when rendered by using onLayout and map them with their index. I can then use each item size to get their offset and use scrollToOffset to jump to the given item (by using scrollToItem function in the code below). The issue here is that I am not able to jump to certain item until that item has been rendered.
My temporary solution for that is by tweaking initialNumberToRender close to the number of data and set the windowSize props as high as possible so that all of the items will be rendered (even though the user doesn't scroll down).
getOffsetByIndex = (index) => {
let offset = 0;
for (let i = 0; i < index; i++) {
const elementLayout = this.layoutMap[index];
if (elementLayout && elementLayout.height) {
offset += this.layoutMap[i].height;
}
}
return offset;
};
scrollToItem = (index) => {
const offset = this.getOffsetByIndex(index);
this.flatListRef.scrollToOffset(offset);
};
addToLayoutMap = (layout, index) => {
this.layoutMap[index] = layout;
};
render(){
return(
<FlatList
ref={this.flatListRef}
data={this.state.data}
renderItem={() => <View onLayout={this.addToLayoutMap}> <SomeComponent/> </View>}
initialNumToRender={this.state.data.length / 5}
windowSize={this.state.data.length}
/>
);
}
This solution works with small number of data, but when the data is large (containing ~300 of rows), it will take long time to be rendered get all the item size, preventing the user to jump to the last item directly for example.
Is there any efficient way to do it?
Also, rendering all the rows is so memory consumptive and negates the benefit of using FlatList.
You can dynamically split your data according to scroll direction. If scroll goes up prepend data to your state and same for opposite direction. Then use onScrollToIndexFailed like this :
<FlatList
ref={this.flatListRef}
data={this.state.data}
renderItem={() => <View> <SomeComponent /> </View>}
initialNumToRender={this.state.data.length / 5}
onEndReached={(e) => {
// Append data
}}
onScroll={(e) => {
if (e.nativeEvent.contentOffset.y == 0) {
// Prepend data
}
}}
onScrollToIndexFailed={(error) => {
this.flatListRef.scrollToOffset({ offset: error.averageItemLength * error.index, animated: true });
setTimeout(() => {
if (this.state.data.length !== 0 && this.flatListRef !== null) {
this.flatListRef.scrollToIndex({ index: error.index, animated: true });
}
}, 100);
}}
/>
You can workaround this issue. This worked for me and took me a lot of time to get that work :))

Can I use multiple or nested elements in the Label of a Picker Item in React Native?

I'm using React Native with NativeBase and would like to make the labels of my Picker more complicated than just one plain string of text.
But is it even possible to pass elements as the label, say multiple child elements wrapped in a single top-level element?
Or do Pickers only support plain text as labels?
As requested by bennygenel, here's a version of what I've tried:
export default class ThingPicker extends React.Component {
render() {
const {
initialThing,
things,
onThingChanged,
} = this.props;
const orderedThings = things.sort();
return (
<Picker
selectedValue={initialThing}
onValueChange={onThingChanged}>
{buildThingItems(orderedThings)}
</Picker>
);
}
}
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = th === "BMD" ? (<Text key={th} label={"foo"} value={"bar"}}>Hello</Text>)
: (<Picker.Item key={th} label={th} value={th} />);
return it;
});
}
Yes! It is possible, it just might not look very "right" for React/JSX code. Just create the elements you need and assign them to the label field:
function buildThingItems(orderedThings) {
let items = orderedThings.map(th => {
const it = (<Picker.Item
key={th}
label={currency === "BMD" ? (<Text>Hello</Text>) : th}
value={th} />);
return it;
});
}