如何在 React-Native 中处理平面列表项的状态
How to handle state on Flat List Items in React-Native
我正在为 React-Native 的 FlatList 组件的项目设置一个计数器。如何在用户每次按下“+”或“-”按钮时更新列表项?
我目前可以更新状态值,但是列表不显示新状态。我已经尝试将 extraData 组件添加到 FlatList,但它似乎并没有更新。
这是数据结构
data: [
{
id: 1,
name: "Bread",
price: "400",
imageS: "../resources/pan-corteza-blanda.jpg",
quantity: 2
},
... more data
这是处理增量的函数
handleIncrement = i => {
this.setState(state => {
const formatData = state.data.map((item, j) => {
console.log("Id", i + " /// " + item.id);
if (item.id === i) {
item.quantity = item.quantity + 1;
return item;
} else {
return item;
}
});
console.log("FormatData" + formatData); //Displays the correct quantity of the item updated
return {
formatData
};
});
};
这是列表组件
<FlatList
data={this.state.data}
style={styles.list}
extraData={this.state.data}
renderItem={this.renderItem}
/>
我希望在用户每次按下“+”或“-”按钮时使用正确的数量值更新列表项的文本组件。
this.state.data
在您的 handleIncrement
上永远不会改变,这就是您传递给 FlatList
的内容。这就是 FlatList
不更新的原因。
handleIncrement
运行后,您的状态唯一发生变化的是:
{
formatData: [...stuff here]
}
也许您想传递 this.state.formatData
或在 handleIncrement
中将其重命名为 data
。
此外,您的状态结构可能更适合用作地图,其中的键是 itemId。这样您就不需要在每次要增加数量时都映射整个列表。
例如
{
1: {
id: 1,
name: "Bread",
price: "400",
imageS: "../resources/pan-corteza-blanda.jpg",
quantity: 2
},
// more data...
}
现在,您的 handleIncrement
看起来像这样:
handleIncrement = itemId => this.setState(prevState => ({
...prevState,
[itemId]: ++prevState[itemId].quantity
}))
您需要更新数据状态而不是返回项目。
handleIncrement = i => {
const item = this.state.data[i];
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + 1 }),
...this.state.data.slice(i + 1)
]
});
};
您可以重构函数并将其用于 -
和 +
。
// pass array index and quantity 1 for + and -1 for -
handleIncrement = (i, qty) => {
const item = this.state.data[i];
if (item && item.quantity === 0 && qty === -1) {
return;
}
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
...this.state.data.slice(i + 1),
],
});
};
下面是使用上述功能的demo,在reactjs中。该函数也可以在 React Native 中使用。
h1, p {
font-family: Lato;
}
.container {
display: flex;
flex-direction: row;
border-bottom-style: solid;
margin-bottom: 5px;
}
.image-container {
flex-grow: 0;
}
.info-container {
display: flex;
margin-left: 10px;
flex-direction: row;
}
.title {
margin-top: 0;
}
.titleContainer {
width: 100px;
}
.cover {
width: 30px;
}
.buttons {
flex-grow: 1;
display: flex;
margin-left: 10px;
}
.incrementButtons {
width: 20px;
height: 20px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class Item extends React.Component {
render() {
return (
<div className="container">
<div className="image-container">
<img className="cover" src={this.props.image} />
</div>
<div className="info-container">
<div className="titleContainer">
<p className="title">{this.props.title}</p>
</div>
<div className="buttons">
<p className="title">{this.props.qty}</p>
<img onClick={() => this.props.increment(this.props.index, -1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/minus-math.png" />
<img onClick={() => this.props.increment(this.props.index, 1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/plus-math.png" />
</div>
</div>
</div>
)
}
}
class App extends React.Component {
state = {
data: [
{
id: 1,
name: 'Avocado',
price: '400',
imageS: 'https://img.icons8.com/metro/26/000000/avocado.png',
quantity: 0,
},
{
id: 6,
name: 'Bread',
price: '300',
imageS: 'https://img.icons8.com/metro/26/000000/bread.png',
quantity: 0,
},
{
id: 2,
name: 'Milk',
price: '300',
imageS: 'https://img.icons8.com/metro/26/000000/milk-bottle.png',
quantity: 0,
},
],
};
handleIncrement = (i, qty) => {
const item = this.state.data[i];
if (item && item.quantity === 0 && qty === -1) {
return;
}
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
...this.state.data.slice(i + 1),
],
});
};
render() {
const items = this.state.data.map((item, index) => (
<Item qty={item.quantity} index={index} key={index} increment={this.handleIncrement} title={item.name} image={item.imageS} />
))
return (
<div>
{items}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>
我正在为 React-Native 的 FlatList 组件的项目设置一个计数器。如何在用户每次按下“+”或“-”按钮时更新列表项?
我目前可以更新状态值,但是列表不显示新状态。我已经尝试将 extraData 组件添加到 FlatList,但它似乎并没有更新。
这是数据结构
data: [
{
id: 1,
name: "Bread",
price: "400",
imageS: "../resources/pan-corteza-blanda.jpg",
quantity: 2
},
... more data
这是处理增量的函数
handleIncrement = i => {
this.setState(state => {
const formatData = state.data.map((item, j) => {
console.log("Id", i + " /// " + item.id);
if (item.id === i) {
item.quantity = item.quantity + 1;
return item;
} else {
return item;
}
});
console.log("FormatData" + formatData); //Displays the correct quantity of the item updated
return {
formatData
};
});
};
这是列表组件
<FlatList
data={this.state.data}
style={styles.list}
extraData={this.state.data}
renderItem={this.renderItem}
/>
我希望在用户每次按下“+”或“-”按钮时使用正确的数量值更新列表项的文本组件。
this.state.data
在您的 handleIncrement
上永远不会改变,这就是您传递给 FlatList
的内容。这就是 FlatList
不更新的原因。
handleIncrement
运行后,您的状态唯一发生变化的是:
{
formatData: [...stuff here]
}
也许您想传递 this.state.formatData
或在 handleIncrement
中将其重命名为 data
。
此外,您的状态结构可能更适合用作地图,其中的键是 itemId。这样您就不需要在每次要增加数量时都映射整个列表。
例如
{
1: {
id: 1,
name: "Bread",
price: "400",
imageS: "../resources/pan-corteza-blanda.jpg",
quantity: 2
},
// more data...
}
现在,您的 handleIncrement
看起来像这样:
handleIncrement = itemId => this.setState(prevState => ({
...prevState,
[itemId]: ++prevState[itemId].quantity
}))
您需要更新数据状态而不是返回项目。
handleIncrement = i => {
const item = this.state.data[i];
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + 1 }),
...this.state.data.slice(i + 1)
]
});
};
您可以重构函数并将其用于 -
和 +
。
// pass array index and quantity 1 for + and -1 for -
handleIncrement = (i, qty) => {
const item = this.state.data[i];
if (item && item.quantity === 0 && qty === -1) {
return;
}
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
...this.state.data.slice(i + 1),
],
});
};
下面是使用上述功能的demo,在reactjs中。该函数也可以在 React Native 中使用。
h1, p {
font-family: Lato;
}
.container {
display: flex;
flex-direction: row;
border-bottom-style: solid;
margin-bottom: 5px;
}
.image-container {
flex-grow: 0;
}
.info-container {
display: flex;
margin-left: 10px;
flex-direction: row;
}
.title {
margin-top: 0;
}
.titleContainer {
width: 100px;
}
.cover {
width: 30px;
}
.buttons {
flex-grow: 1;
display: flex;
margin-left: 10px;
}
.incrementButtons {
width: 20px;
height: 20px;
margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
class Item extends React.Component {
render() {
return (
<div className="container">
<div className="image-container">
<img className="cover" src={this.props.image} />
</div>
<div className="info-container">
<div className="titleContainer">
<p className="title">{this.props.title}</p>
</div>
<div className="buttons">
<p className="title">{this.props.qty}</p>
<img onClick={() => this.props.increment(this.props.index, -1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/minus-math.png" />
<img onClick={() => this.props.increment(this.props.index, 1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/plus-math.png" />
</div>
</div>
</div>
)
}
}
class App extends React.Component {
state = {
data: [
{
id: 1,
name: 'Avocado',
price: '400',
imageS: 'https://img.icons8.com/metro/26/000000/avocado.png',
quantity: 0,
},
{
id: 6,
name: 'Bread',
price: '300',
imageS: 'https://img.icons8.com/metro/26/000000/bread.png',
quantity: 0,
},
{
id: 2,
name: 'Milk',
price: '300',
imageS: 'https://img.icons8.com/metro/26/000000/milk-bottle.png',
quantity: 0,
},
],
};
handleIncrement = (i, qty) => {
const item = this.state.data[i];
if (item && item.quantity === 0 && qty === -1) {
return;
}
this.setState({
data: [
...this.state.data.slice(0, i),
Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
...this.state.data.slice(i + 1),
],
});
};
render() {
const items = this.state.data.map((item, index) => (
<Item qty={item.quantity} index={index} key={index} increment={this.handleIncrement} title={item.name} image={item.imageS} />
))
return (
<div>
{items}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
</script>