使用react-native,我在父App
中创建子组件,并将其位置提供给父this.state.objLocation
内的数组App
。
我可以在渲染后直接将初始位置数据放入数组中,但由于我的子组件是可拖动的,每次它们在拖动时重新渲染时,它会向数组添加一个新的位置对象。
我想避免这种情况,我认为在构造函数中创建this.state = { firstRender: true }
然后在第一次渲染后使用componentDidMount = () => { this.setState({ firstRender: false }) }
将允许我创建一个“门”来停止添加额外的位置对象。
我可以看到,如果我注释掉//componentDidMount = () => { this.setState({ firstRender: false }) }
,那么我将获得多个条目到我的数组,但如果它包含在类中,我绝对没有。
所以我对渲染生命周期和componentDidMount
的解释可能不正确吗?
这是我的代码。
// App
import React, { Component } from 'react';
import { View, Text, } from 'react-native';
import styles from './cust/styles';
import Draggable from './cust/draggable';
const dataArray = [{num: 1,id: 'A',},{num: 2,id: 'B',},{num: 3,id: 'Z',}]
export default class Viewport extends Component {
constructor(props){
super(props);
this.state = {
dID : null,
objLocation: [],
firstRender: true,
};
}
render(){
return (
<View style={styles.mainContainer}>
<View style={styles.draggableContainer}>
<Text>Draggable Container</Text> {dataArray.map( d => { return(
<Draggable
id={d.id}
onLayout={ e=> this.onLayout(e)}
onPanResponderGrant={(dID) =>this.setState({ dID })}
onPanResponderRelease={() => this.setState({dID: null})} /> ) })}
<View style={[styles.findPoint ]} />
</View>
<View style={styles.infoBar}>
<Text>{this.state.dID ? this.state.dID : ''}</Text>{this.compFrame()}
</View>
</View>
);
}
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
componentWillMount = () => {
console.log("START");
}
compFrame = () => {
return(
this.state.objLocation.map( d => {<View style={[styles.findPoint2,{left: d.x, top: d.y, width: d.width, height: d.height} ]} ></View>})
)
}
componentDidMount = () => {
this.setState({firstRender: true })
console.log(this.state.objLocation.length);
}
}
//可拖动
import React, { Component } from 'react';
import { Text, PanResponder, Animated } from 'react-native';
import styles from './styles';
class Draggable extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
};
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
this.props.onPanResponderGrant(this.props.id);
},
onPanResponderMove: Animated.event([ null, {
dx: this.state.pan.x,
dy: this.state.pan.y,
},
]),
onPanResponderRelease: () => {
Animated.spring(this.state.pan, { toValue: { x: 0, y: 0 } }).start();
this.props.onPanResponderRelease();
},
});
}
render() {
return (
<Animated.View
onLayout={ (e) => this.props.onLayout(e) }
{...this.panResponder.panHandlers}
style={[this.state.pan.getLayout(), styles.circleAlt, styles.position]}>
<Text style={styles.textAlt}>Drag me!</Text>
<Text style={styles.textNum}>{this.props.id}</Text>
</Animated.View>
);
}
componentDidMount = () => {
this.props.onLayout(this.props.dragEvent)
}
}
export default Draggable;
// console.log的输出
START xxx
0
{width:108,height:108,x:133.5,y:376.5}
{width:108,height:108,x:133.5,y:78.5}
{width:108,height:108,x:133.5,y:227.5}
答案 0 :(得分:2)
您可以在onLayout函数中设置firstRender状态
onLayout = (e) => {
if ( e && this.state.firstRender) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
firstRender: false,
objLocation: this.state.objLocation.concat([position])
});
}
}
答案 1 :(得分:0)
根据您提供的信息,您的onLayout函数由组件调用,因此它不包含在组件生命周期过程中,因此当组件完成其生命周期后,它将在安装后进入componentDidMount(不调用onLayout func) &安培;因此将firstRender状态更改为false,因此每次从true变为false时拖动组件。 我希望这能解释
答案 2 :(得分:0)
我觉得我已经入侵了它,让它发挥作用,所以请纠正我以纠正程序。
这是来自App
的onLayout方法。我已经包含了一个if
语句,用于检查新位置数组长度是否与可拖动项目所基于的dataArray长度相等。
看起来像这样。
onLayout = (e) => {
if ( this.state.objLocation.length != dataArray.length ) {
if ( e ) {
const n = e.nativeEvent.layout;
const position = {
width: n.width,
height: n.height,
x: n.x,
y: n.y
}
console.log(position);
this.setState({
objLocation: this.state.objLocation.concat([position])
});
}
}
}