注意:我在那里发布了一个答案,我个人认为这是迄今为止最好的解决方案.虽然它不是最高级别的答案,但根据我得到的结果,它非常有效.
--------------------------------------------- 原始问题 --- -------------------------------------------------- -
假设我正在写一个Twitter克隆,但更简单.我将每个项目放在FlatList中并渲染它们.
为了"喜欢"一个帖子,我按下帖子上的"喜欢"按钮,"喜欢"按钮变成红色,我再次按下它,它变成灰色.
这就是我到目前为止:我存储了所有加载的帖子this.state,每个帖子都有一个名为"likes"的属性,它是boolean,表示该用户是否喜欢这个帖子,当用户按下"喜欢"时,我去了以state.posts和更新liked该职位的性质,然后利用this.setState更新的帖子,像这样:
// 1. FlatList
<FlatList
...
data={this.state.posts}
renderItem={this.renderPost}
...
/>
// 2. renderPost
renderPost({ item, index }) {
return (
<View style={someStyle}>
... // display other properties of the post
// Then display the "like" button
<Icon
name='favorite'
size={25}
color={item.liked ? 'red' : 'gray'}
containerStyle={someStyle}
iconStyle={someStyle}
onPress={() => this.onLikePost({ item, index })}
/>
...
</View>
);
}
// 3. onLikePost
likePost({ item, index }) {
let { posts } = this.state;
let targetPost = posts[index];
// Flip the 'liked' property of the targetPost
targetPost.liked = !targetPost.liked;
// Then update targetPost in 'posts'
posts[index] = targetPost;
// Then reset the 'state.posts' property
this.setState({ posts });
}
Run Code Online (Sandbox Code Playgroud)
然而,这种方法很有效.当我按下它时,"喜欢"按钮的颜色翻转,但通常需要大约1秒钟才能改变颜色.我想要的是当我按下它时,颜色几乎会同时翻转.
我知道为什么会发生这种情况,我可能不会使用this.setState,因为当我这样做时,posts状态发生了变化,所有的帖子都被重新渲染,但我还能尝试其他方法吗?
tom*_*wel 13
您可以设定extraData在FlatList:
<FlatList
...
extraData={this.state}
data={this.state.posts}
renderItem={this.renderPost}
...
/>
Run Code Online (Sandbox Code Playgroud)
当state.posts或者state.posts项目改变时,FlatList将重新渲染.
用于告知列表重新呈现的标记属性(因为它实现了PureComponent).如果你的任何renderItem,Header,Footer等函数依赖于数据道具之外的任何东西,请将其粘贴在此处并进行不可变处理.
如果您正在测试Android而不是尝试关闭开发人员模式.或者您是否正在使用某些API并更新服务器上的帖子并更新与服务器响应相对应的UI中的like按钮?如果是这种情况请告诉我,我也遇到了这个并且我解决了它.另外,我已经在代码中注释了第二行,这是不需要的.
// 1. FlatList
<FlatList
...
data={this.state.posts}
renderItem={this.renderPost}
...
/>
// 2. renderPost
renderPost({ item, index }) {
return (
<View style={someStyle}>
... // display other properties of the post
// Then display the "like" button
<Icon
name='favorite'
size={25}
color={item.liked ? 'red' : 'gray'}
containerStyle={someStyle}
iconStyle={someStyle}
onPress={() => this.onLikePost({ item, index })}
/>
...
</View>
);
}
// 3. onLikePost
likePost({ item, index }) {
let { posts } = this.state;
let targetPost = posts[index];
// Flip the 'liked' property of the targetPost
targetPost.liked = !targetPost.liked;
// Then update targetPost in 'posts'
// You probably don't need the following line.
// posts[index] = targetPost;
// Then reset the 'state.posts' property
this.setState({ posts });
}
Run Code Online (Sandbox Code Playgroud)
不要误会我的意思,@ ShubhnikSingh的回答确实有帮助,但是我撤回了它,因为很久以前我找到了解决该问题的更好方法,最后我记得将其发布在这里。
假设我的帖子包含以下属性:
{
postId: "-L84e-aHwBedm1FHhcqv",
date: 1525566855,
message: "My Post",
uid: "52YgRFw4jWhYL5ulK11slBv7e583",
liked: false,
likeCount: 0,
commentCount: 0
}
Run Code Online (Sandbox Code Playgroud)
Where liked表示查看此帖子的用户是否喜欢此帖子,这将确定“赞”按钮的颜色(默认情况下为灰色,如果为,则为红色liked == true)。
以下是重新创建我的解决方案的步骤:进行“发布”,Component并在中进行呈现FlatList。PureComponent如果您没有传递给您的任何道具,Post例如可以看成不浅的数组或对象,则可以使用React 。如果您不知道这意味着什么,请按照下面的步骤使用常规Component和覆盖shouldComponentUpdate。
class Post extends Component {
// This determines whether a rendered post should get updated
// Look at the states here, what could be changing as time goes by?
// Only 2 properties: "liked" and "likeCount", if the person seeing
// this post ever presses the "like" button
// This assumes that, unlike Twitter, updates do not come from other
// instances of the application in real time.
shouldComponentUpdate(nextProps, nextState) {
const { liked, likeCount } = nextProps
const { liked: oldLiked, likeCount: oldLikeCount } = this.props
// If "liked" or "likeCount" is different, then update
return liked !== oldLiked || likeCount !== oldLikeCount
}
render() {
return (
<View>
{/* ...render other properties */}
<TouchableOpacity
onPress={() => this.props.onPressLike(this.props.postId)}
>
<Icon name="heart" color={this.props.liked ? 'gray' : 'red'} />
</TouchableOpacity>
</View>
)
}
}
Run Code Online (Sandbox Code Playgroud)
然后,创建一个PostList组件,该组件将负责处理加载帖子的逻辑和类似交互的处理:
class PostList extends Component {
/**
* As you can see, we are not storing "posts" as an array. Instead,
* we make it a JSON object. This allows us to access a post more concisely
* than if we stores posts as an array. For example:
*
* this.state.posts as an array
* findPost(postId) {
* return this.state.posts.find(post => post.id === postId)
* }
* findPost(postId) {
* return this.state.posts[postId]
* }
* a specific post by its "postId", you won't have to iterate
* through the whole array, you can just call "posts[postId]"
* to access it immediately:
* "posts": {
* "<post_id_1>": { "message": "", "uid": "", ... },
* "<post_id_2>": { "message": "", "uid": "", ... },
* "<post_id_3>": { "message": "", "uid": "", ... }
* }
* FlatList wants an array for its data property rather than an object,
* so we need to pass data={Object.values(this.state.posts)} rather than
* just data={this.state.posts} as one might expect.
*/
state = {
posts: {}
// Other states
}
renderItem = ({ item }) => {
const { date, message, uid, postId, other, props, here } = item
return (
<Post
date={date}
message={message}
uid={uid}
onPressLike={this.handleLikePost}
/>
)
}
handleLikePost = postId => {
let post = this.state.posts[postId]
const { liked, likeCount } = post
const newPost = {
...post,
liked: !liked,
likeCount: liked ? likeCount - 1 : likeCount + 1
}
this.setState({
posts: {
...this.state.posts,
[postId]: newPost
}
})
}
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={Object.values(this.state.posts)}
renderItem={this.renderItem}
keyExtractor={({ item }) => item.postId}
/>
</View>
)
}
}
Run Code Online (Sandbox Code Playgroud)
综上所述:
1)编写一个自定义组件(Post),以呈现“ FlatList”中的每个项目
2)覆盖自定义组件(Post)函数的“ shouldComponentUpdate”,以告知组件何时更新
处理父组件(PostList)中的“喜欢状态” ,并将数据向下传递给每个子组件
| 归档时间: |
|
| 查看次数: |
16333 次 |
| 最近记录: |