I am trying to create a custom range slider, and to get the value of the translationX and pass it as a prop and/or into my redux, however this has seemed impossible, as it does not update, even when I use useState.
Has any one experienced this issue in the past.
Below is my current code
const CustomSlider = ({ onPressOut, testData }) => {
const translateX = useSharedValue(SCREEN_WIDTH / 2);
const context = useSharedValue({ x: SCREEN_WIDTH / 2 });
console.log(testData);
const handleGesture = Gesture.Pan()
.onStart(() => {
context.value = { x: translateX.value };
})
.onUpdate(event => {
translateX.value = event.translationX + context.value.x;
if (translateX.value < SCREEN_WIDTH / 2) {
translateX.value = Math.max(translateX.value, MIN_TRANSLATE_X);
} else {
translateX.value = Math.min(translateX.value, MAX_TRANSLATE_X);
}
testData(translateX.value);
});
const rBottomSheetStyle = useAnimatedStyle(() => {
return {
left: translateX.value,
};
});
return (
<View style={styles.container}>
<View style={styles.negativeLineStyle} />
<View style={styles.positiveLineStyle} />
<GestureDetector gesture={handleGesture}>
<AnimatedTouchableOpacity
activeOpacity={1}
onPressOut={onPressOut}
style={[rBottomSheetStyle, styles.rangeSliderContainer]}>
<LinearGradient
colors={[SECONDARY, PRIMARY]}
start={[1, 0.9]}
end={[1, 0]}
style={styles.rangeSliderStyle}
/>
</AnimatedTouchableOpacity>
</GestureDetector>
</View>
);
};
Related
I'm using react three fiber and i have two components
one to make a box and the other is to make an array of this box
here's how they look like, the platform component:
export function Plat() {
const [active, setActive] = useState(0)
const { scale } = useSpring({ scale: active ? 1 : 0.4 })
const [mat] = useState(() => new THREE.TextureLoader().load('/matcap.png'))
function Shape(props) {
return (
<animated.mesh {...props} scale={scale} onPointerOver={() => setActive(Number(!active))} >
<RoundedBox args={[60,20,60]} radius={4} smoothness={4} position={[0, -10, 0]} dispose={null} >
<meshMatcapMaterial matcap={mat} />
</RoundedBox>
</animated.mesh>
);
}
useEffect(() => {
(function() {
setActive((1))
})();
},[]);
return (
<Shape />
)
}
and the component that makes an array of this platform:
import {Plat} from './Plat'
export default function Boxes() {
function MyShape(props) {
return (
<mesh {...props} >
<Plat />
</mesh>
);
}
const [shapes, setShapes] = useState([<MyShape key={0} position={[100, 100, 100]} />, <MyShape key={1} position={[120, 120, 120]} />, <MyShape key={2} position={[130, 130, 130]} />]);
return (
<group >
{[...shapes]}
</group>
)
}
(I have more than 3 elements in the array)
I wanna know if there's a way to access the variables inside each of the array's platform components
how would I do something like this:
console.log(shapes[2].position) or change the position of this specific shape in the array
or this
shapes[1].setActive(1)
is it even possible?
Few pointer
Avoid nesting functional components
Plat
Shape // declare this outside and pass it the params from parent
If you need to change the position of the children, consider creating a array with the information you need to change
const [shapes, setShapes] = useState<>([{ key: 1, position: { x: 5, y: 10 } }])
const changeShapePostions = (key) => {
setShapes(items => {
return items.map(shape => {
if (shape.id === key) {
return { ...shape, position: { x: updatedX, y: updated: y} }
} else {
return shape
}
}
}
}
const setActive = (key) => {
setShapes(items => {
return items.map(shape => {
if (shape.id === key) {
return { ...shape, isActive: true }
} else {
return shape
}
}
}
}
return (
<group >
{
shapes.map(shape => {
return (<MyShape key={shape.key} position={shape.position} setActive={setActive} />)
}
}
</group>
)
you can check standard practices on working with arrays
Hope it helps in some ways
I'm new to react-native and I have an input where I can choose multiple days of a week, if I click on a day which is alreadyAdded the day is removed from selectedDays array, however when I click on a day I get the following error:
TypeError: selectedDays.includes is not a function. (In selectedDays.includes(index+1) selectedDays.includes is undefined
My code:
const [ dayOptions, setDayOptions ] = useState([ 'Lunes','Martes','Miercoles','Jueves','Viernes','Sabado','Domingo']);
const [ selectedDays, setSelectedDays ] = useState([1]);
const clickedDay = (id)=>
{
const index = selectedDays.indexOf(id);
if (index > -1)
{
setSelectedDays(selectedDays.splice(index, 1));
}
else
{
setSelectedDays(selectedDays.push(id));
}
}
<View style={{ width:'100%',height:45,flexDirection:'row',alignItems:'center',flexWrap:'nowrap', justifyContent:'space-between' }}>
{dayOptions.map((option,index) => {return (
<TouchableOpacity key={option.title} onPress = {() => {clickedDayOptions(index+1) }} style={{ width:'13.2%', height:'100%', flexDirection:'row', alignItems:'center',justifyContent:'center', borderRadius:5,borderWidth:1, borderColor:'rgba(0,0,0,0.2)', ...selectedDays.includes(index+1) ? { backgroundColor: 'rgb(255,52,89)' } : { backgroundColor:'white' }, }}>
<Text style={{ fontWeight:'bold',fontSize:14, ...selectedDays.includes(index+1) ? { color: 'white' } : { color:'rgb(68,68,68)' }, }}>{ option }</Text>
</TouchableOpacity>)
})}
</View>
I tried changing includes for indexOf() > 1 and I get the same error, I usually get this when it's not an array but I defined selectedDays as an array in hooks...
setSelectedDays(selectedDays.push(id)); Generally Array.prototype.push will return the length of the array after push operation is done, so here we are making Array to number so that you are getting indexOf, includes is not a function error because it's a number type
Try like below
const clickedDay = (id) => {
const index = selectedDays.indexOf(id);
if (index > -1) {
selectedDays.splice(index, 1)
setSelectedDays([...selectedDays]);
} else {
setSelectedDays([...selectedDays, id]);
}
};
const clickedDay = (id) => {
const index = selectedDays.indexOf(id);
if (index > -1) {
const days = selectedDays.filter((idx) => idx !== id);
setSelectedDays(days);
} else {
setSelectedDays([...selectedDays, id]);
}
};
I am trying to declare and return multiple HOC's from any array, but keep being returned a "Functions are not valid as a React child." Error. Has anyone ran into this issue before?
JS:
....
const styles = {
fontFamily: "sans-serif",
textAlign: "center"
};
const withRequestAnimationFrame = () => WrappedComponent => {
class RequestAnimationFrame extends Component {
state = {
timeStamp: 0,
newItem: "Test"
};
componentDidMount() {
const min = 1;
const max = 100;
const rand = Math.floor(Math.random() * (max - min + 1)) + min;
this.setState({ timeStamp: this.state.timeStamp + rand });
}
render() {
return (
<WrappedComponent {...this.state} {...this.props} />
)
}
}
return RequestAnimationFrame;
};
const App = ({ timeStamp, newItem }) => (
<div style={styles}>
<h1>{timeStamp}</h1>
<p>{newItem}</p>
</div>
);
const arrayItems = ["EnhancedApp", "EnhancedApp2"];
const Products = ({ items }) => {
return (
items.map((item, index) => (
item = withRequestAnimationFrame()(App)
))
)
};
function Product() {
return (
<div>
<Products items={arrayItems} />
</div>
)
}
render(<Product />, document.getElementById("root"));
This line is the problem:
item = withRequestAnimationFrame()(App)
What your doing there is assigning result of withRequestAnimationFrame()(App)
function to item which is definetly not what you wanted. I assume you wanted to
render there multiple instances of withRequestAnimationFrame component. You can
do it like this:
items.map((item, index) => (
const NewComponent = withRequestAnimationFrame(item)(App);
return <NewComponent key={index}/>
))
Second problem is that you are not passing item prop to the wrapped component.
To pass item prop you should do:
const withRequestAnimationFrame = (item) => WrappedComponent => {
class RequestAnimationFrame extends React.Component {
state = {
timeStamp: 0,
newItem: item
};
My issue if the following:
The duration of the video is 6.357 seconds. The progress.currentTime only goes to 6.154 and stops.
Since that this.state.progress = 0.97 (not 1.0). As an outcome my ProgressBar doesn't go to the end. It stops on 0.97 position and onProgressPress() doesn't work.
Could someone please assist?
Here is my code:
export default class VideoComp extends Component {
state = {
paused: false,
progress: 0,
duration: 0
}
onProgressPress = (e) => {
const position = e.nativeEvent.locationX;
const progress = (position / 250) * this.state.duration;
this.player.seek(progress);
}
onMainButtonPress = () => {
if(this.state.progress >= 1) {
this.player.seek(0);
};
this.setState(state => {
return {
paused: !state.paused
}
})
}
handleEnd = () => {
this.setState({
paused: true
})
}
handleProgress = (progress) => {
this.setState({
progress: progress.currentTime / this.state.duration
});
}
handleLoad = (meta) => {
this.setState({
duration: meta.duration
})
}
render() {
const { width } = Dimensions.get('window');
const height = width * 0.5625;
return(
<View style = {styles.videoWrapper}>
<Video
source = {{uri: this.props.videoURL}}
ref = {ref => this.player = ref}
style = {{width: '100%', height}}
paused = {this.state.paused}
resizeMode = 'contain'
onLoad = {this.handleLoad}
onProgress = {this.handleProgress}
onEnd = {this.handleEnd}
/>
<View style = {styles.controls}>
<TouchableWithoutFeedback onPress = {this.onMainButtonPress}>
<IconSimpleLine name = {!this.state.paused ? 'control-pause' : 'control-play'} color = {text} size = {20}/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress = {this.onProgressPress}>
<View>
<ProgressBar
progress = {this.state.progress}
width = {250}
height = {5}
color = {text}
borderColor = {text}
unfilledColor = 'rgba(255, 255, 255, 0.3)'
/>
</View>
</TouchableWithoutFeedback>
<Text style = {styles.duration}>
{secondsToTime(Math.floor(this.state.progress * this.state.duration))}
</Text>
</View>
</View>
)
}
}
UPDATE
I tried the next:
handleProgress = (progress) => {
this.setState({
progress: Math.floor(progress.currentTime) / this.state.duration
});
}
handleLoad = (meta) => {
this.setState({
duration: Math.floor(meta.duration)
})
}
The ProgressBar line now goes to the very end but it moves by a second. I mean, it moves a bit, stops on one second, moves a bit farther, stops on one second and so on. It doesn't move smoothly (each millisecond).
But it's not the correct solution.
the Video component has an onEnd prop. use that to update your state to 100%
Try to user parseFloat() for calculation purpose.
in your question, I don't know which value is coming in float or in a fraction number but just for example use as this.
this.setState({
progress: parseFloat(progress.currentTime / this.state.duration)
});
and
const progress = parseFloat(position / 250)) * this.state.duration;
Hope it will help you.
I have a simple Notes React Native app and I am able to add and get data to it, but I am not sure how to remove/update data. The main problem is in getting the part where I tell firebase which data to remove. How can I pass a firebase key to a 'delete' function that takes the key as parameter and remove it from firebase.
I'm an absolute beginner at React Native, my code is the following:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
all_notitas: [],
notita_text: ''
};
};
componentWillMount() {
const notitasRef = firebase.database().ref('notitas');
this.listenForNotitas(notitasRef);
};
listenForNotitas = (notitasRef) => {
notitasRef.on('value', (dataSnapshot) => {
var aux = [];
dataSnapshot.forEach((child) => {
aux.push({
date: child.val().date,
notita: child.val().notita
});
});
this.setState({all_notitas: aux});
});
}; // listenForNotitas
render() {
let show_notitas = this.state.all_notitas.map((val, key) => {
return (
<Notita
key={key}
keyval={key}
val={val}
eventDeleteNotita={()=>this.deleteNotita(key)}> // I THINK THIS IS THE PROBLEM
</Notita>
);
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>NOTITAS</Text>
</View>
<ScrollView style={styles.scrollContainer}>
{show_notitas}
</ScrollView>
<View style={styles.footer}>
<TouchableOpacity
style={styles.addButton}
onPress={this.addNotita.bind(this)}>
<Text style={styles.addButtonText}>+</Text>
</TouchableOpacity>
<TextInput
style={styles.textInput}
placeholder='>>> Escribir notita'
placeholderTextColor='white'
underlineColorAndroid='transparent'
onChangeText={(notita_text) => (this.setState({notita_text}))}
value={this.state.notita_text}>
</TextInput>
</View>
</View>
);
}
addNotita() {
if (this.state.notita_text) {
var d = new Date();
dataForPush = {
'date': d.getDate() + '-' + d.getMonth() + '-' + d.getFullYear(),
'notita': this.state.notita_text
};
firebase.database().ref('notitas').push(dataForPush);
this.state.all_notitas.push(dataForPush);
this.setState(
{
all_notitas: this.state.all_notitas,
notita_text: '', // Limpiar input
}
)
} // end if
} // addNotita
When I do 'console.log(key)', it returns an int like 0, 1, 2, etc. It should return a firebase key like '-LRtghw8CjMsftSAXMUg' for example. I don't know what I am doing wrong and how to fix it.
deleteNotita(key) {
firebase.database().ref('notitas').child('' + key).remove()
/*
let updates = {};
console.log(key);
console.log(updates['/notitas/' + key]);
updates['/notitas/' + key] = null;
firebase.database().ref().update(updates); */
this.state.all_notitas.splice(key, 1);
this.setState({all_notitas: this.state.all_notitas});
} // deleteNotita
}
You're dropping the key from Firebase when you're adding the notes to aux. The solution is to also keep the key from Firebase in there:
notitasRef.on('value', (dataSnapshot) => {
var aux = [];
dataSnapshot.forEach((child) => {
aux.push({
date: child.val().date,
notita: child.val().notita,
id: child.key
});
});
this.setState({all_notitas: aux});
}
And then pass that value to deleteNotita with:
this.deleteNotita(val.id)