Индекс выбранного значения остается одинаковым для всех динамических счетчиков React-native
Я пытаюсь сделать динамический экран, где я добавляю несколько CustomSpinners
с помощью forEach
Цикл в реакции-родной.
Проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда я выбираю значение из любого счетчика, это значение обновляется для всех счетчиков, так как индекс остается неизменным. Предположим, когда я нажимаю на цветную кнопку и выбираю Cyna с индексом 2 и когда я печатаю this.setState({name: index});
он снова вызывает метод Render, и весь вид снова рисует и как itemName={this.state.name}
установлен на 2, поэтому он будет автоматически выбирать все значения счетчика на основе индекса 2, что я хочу, чтобы, когда я нажимал на Color spinner и выбирал голубой цвет, обновлялся только тот Color Spinner вместо обновления всех счетчиков с тем же индексом.
Кто-нибудь может дать мне знать, как этого добиться? Я уже почесал голову за последние 2 дня по этому поводу. Пожалуйста, дайте мне знать ваши предложения, которые действительно очень мне помогут.
Вот мой код:-
onClickColor(data) {
this.setState({ name: index });
}
renderSpinerData(item) {
return <CustomDynamicSpinner
title={"Chosse " + item.label}
listArray={item.options}
onClick={(data,index) => this.onClickDropdown(data,index)}
itemName={this.state.name}
btnStyle={{
height: 42,
marginBottom: 2,
borderBottomWidth: 1 / 2,
justifyContent: "center"
}}
txtColor={appColor.lightGrey}
style={{
height: 42,
marginBottom: 2,
borderBottomWidth: 1 / 2
}}
closeIconButtonStyle={styles.closeButtonStyle}
/>
};
renderConfigurableProductDetail() {
let array=[];
if (CustomConfigArray.length>0){
array = CustomConfigArray;
} else {
array = this.props.ProductDetailState.productData.configurable;
}
{
return array.map((item) => {
if(item.label!="Size"){
return (
<View style={{ flex: 1, backgroundColor: "white", flexDirection: "column", marginTop: 8 }}>
<CustomText style={{ fontSize: 16, fontFamily: "futuraLigtBt", marginLeft: 6, paddingLeft: 15, paddingRight: 15, paddingTop: 5, paddingBottom: 5 }}>
{item.label}
</CustomText>
{this.renderSpinerData(item)}
</View>;
)
}
})
}
};
Мой класс CustomSpiner:-
class DynamicListViewModal extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: ds.cloneWithRows(this.props.listArray),
listArray: this.props.listArray
};
this.handleClick = this.handleClick.bind(this);
this.renderRow = this.renderRow.bind(this);
this.renderList = this.renderList.bind(this);
}
handleClick(data, index) {
this.props.onClick(data, index);
this.props.onClose();
}
renderRow(rowData) {
const separatorStyle = this.props.separatorStyle;
const rowTextStyle = this.props.rowText;
const rowStyle = this.props.rowStyle;
const rowId = this.props.listArray.indexOf(rowData);
let separator = <View style={separatorStyle} />;
let row = (
<View style={rowStyle}>
<Text style={rowTextStyle}>{rowData.label}</Text>
</View>
);
if (this.props.renderRow) {
row = this.props.renderRow(rowData, rowId);
}
return (
<View>
<TouchableOpacity onPress={() => this.handleClick(rowData, rowId)}>
{row}
</TouchableOpacity>
{separator}
</View>
);
}
renderList() {
const listViewStyle = this.props.listViewStyle || DefaultStyles.listView;
return (
<ListView
style={listViewStyle}
dataSource={this.state.dataSource}
renderRow={(rowData) => this.renderRow(rowData)}
automaticallyAdjustContentInsets={false}
enableEmptySections={true}
/>
);
}
render() {
const containerStyle = this.props.containerStyle;
const topBarStyle = this.props.topBarStyle;
const iconContainerStyle = this.props.iconContainerStyle;
const closeIconButtonStyle = this.props.closeIconButtonStyle;
const titleStyle = this.props.titleStyle;
const title = this.props.title;
return <View style={containerStyle}>
<View style={topBarStyle}>
<View style={iconContainerStyle} />
<Text style={[titleStyle, { fontWeight: "bold", fontSize: 17 }]}>
{title}
</Text>
<TouchableOpacity style={iconContainerStyle} onPress={() => this.props.onClose()}>
<Image source={require("../../assets/cancel.png")} style={closeIconButtonStyle} />
</TouchableOpacity>
</View>
{this.renderList()}
</View>;
}
}
class CustomDynamicSpinner extends Component {
constructor(props) {
super(props);
this.state = {
data: this.props.data,
popoverIsOpen: false
};
this.onClick = this.onClick.bind(this);
}
onClick(data) {
console.log("selected data:", data);
}
render() {
const onClick = this.props.onClick || this.onClick;
return <View>
<TouchableOpacity style={this.props.btnStyle} onPress={() => this.setState(
{ popoverIsOpen: true }
)}>
<Text style={{ color: this.props.txtColor }}>
{(this.props.itemName!="value" || this.props.itemName == 0) ? this.props.listArray[this.props.itemName].label : "Please select"}
</Text>
</TouchableOpacity>
<Modal animationType={"slide"} transparent={false} visible={this.state.popoverIsOpen} onRequestClose={() => {
console.log("Modal has been closed.");
}}>
<View>
<DynamicListViewModal listArray={this.props.listArray} title={this.props.title} onClick={onClick} onClose={() => this.setState(
{ popoverIsOpen: false }
)} containerStyle={this.props.containerStyle} listViewStyle={this.props.listViewStyle} separatorStyle={this.props.separatorStyle} topBarStyle={this.props.topBarStyle} titleStyle={this.props.titleStyle} iconContainerStyle={this.props.iconContainerStyle} closeIconButtonStyle={this.props.closeIconButtonStyle} rowTextStyle={this.props.rowTextStyle} rowStyle={this.props.rowStyle} />
</View>
</Modal>
</View>;
}
}
Ответ от Api:-
"configurable": [{
"id": "142",
"code": "size",
"label": "Size",
"options": [{
"attribute_id": "142",
"atribute_code": "size",
"id": "171",
"label": "XL",
"products": [
"2071",
"2074"
]
}, {
"attribute_id": "142",
"atribute_code": "size",
"id": "172",
"label": "L",
"products": [
"2072"
]
}]
},
{
"id": "93",
"code": "color",
"label": "Color",
"options": [{
"attribute_id": "93",
"atribute_code": "color",
"id": "50",
"label": "Blue",
"products": [
"2071"
]
},
{
"attribute_id": "93",
"atribute_code": "color",
"id": "60",
"label": "Black",
"products": [
"2072"
]
}, {
"attribute_id": "93",
"atribute_code": "color",
"id": "64",
"label": "Cyna",
"products": [
"2072"
]
}, {
"attribute_id": "93",
"atribute_code": "color",
"id": "61",
"label": "White",
"products": [
"2071",
"2074"
]
}
]
},
{
"id": "148",
"code": "format",
"label": "Format",
"options": [{
"attribute_id": "148",
"atribute_code": "format",
"id": "102",
"label": "Download",
"products": [
"2072",
"2071",
"2074"
]
},
{
"attribute_id": "148",
"atribute_code": "format",
"id": "103",
"label": "File",
"products": [
"2071",
"2074"
]
}
]
}
]
Ваша помощь будет принята с благодарностью!!!
С уважением
2 ответа
Когда новое состояние зависит от предыдущего состояния, вы должны использовать формат setState((prevState, props) => {}), см. Ссылку в документе. В любом случае вы никогда не должны изменять состояние напрямую, и это то, что делает эта строка selectValue[index] = значение, так как selectValue является просто ссылкой на this.state
Вот что вам нужно сделать:
// load selectedDropDownValue data from state with the item's id
// pass the item value to the change function
<Picker
selectedValue={this.state.selectedDropDownValue[item.id]}
onValueChange={(itemValue, itemIndex) => this.onClickDropdown(itemValue, itemIndex, item)}
>
{this.loadData(item)}
</Picker>
onClickDropdown(data, index, item){
// save each items selected data with their id
this.setState((prevState) => {
const value = Object.assign({}, prevState.selectedDropDownValue, { [item.id]: data});
return { selectedDropDownValue: value};
});
}
Ваша проблема в том, что name
является частью состояния родительского компонента. Всякий раз, когда onClickColor
вызывается, родительский компонент обновляется, вынуждая все спиннеры перерисовывать вместе с ним.
Так как ваш вопрос имеет react-redux
тег, я предполагаю, что ваше приложение использует redux
также. Если это так, то самое простое решение - переместить name
в магазин редукса и пусть CustomDynamicSpinner
читать name
прямо из магазина:
import { connect } from 'react-redux'
...
const mapStateToProps = (state) => ({
itemName: state.whateverPath.name
})
connect(mapStateToProps)(CustomDynamicSpinner)
И не позволяйте компоненту, содержащему CustomDynamicSpinner
читать name
из магазина редукса. Если какая-либо часть этого компонента нуждается в этой информации, вам следует создать дополнительный дочерний компонент, доступный для магазина.