【问题标题】:Redux / React Native State gets values from previous states and does not update/re-render correctlyRedux / React Native State 从以前的状态中获取值并且不能正确更新/重新渲染
【发布时间】:2020-04-14 13:52:02
【问题描述】:

这里发生了很多奇怪的事情,我不知道从哪里开始。最可笑的是,以前还好好的,突然就停了。

这是流程:

  1. screens/Add.js => 我在 State 中创建了一个 post 对象,将它传递给我的 PostAPI => firebase => 添加到 redux store => 在 FeedScreen 中显示。
  2. 重定向到screens/feed.js。帖子会在几秒钟后出现。到现在为止一切都很好。
  3. 如果我喜欢这篇文章,它会将post.likes.total 加一。我在 redux 存储中通过 ID 查找并更新数组 => 新状态重新呈现通过 mapState ToProps 接收帖子的帖子列表。更改按预期显示。
  4. 现在我创建一个新帖子...它和上面的一样。
  5. 新帖子获得的点赞数与我刚刚点击的上一个帖子相同!当我点击以前创建的帖子时,所有未来的帖子都会获得相同数量的以前的喜欢,并且也会更新。当点击刚刚创建的那个时,它只会更新自己。单击上一个,它会更新自身和以下内容。点击第 3 条帖子会更新自身和 2 条关注,依此类推。
  6. 如果我重新加载页面,点赞会从数据库中正确加载,但使用上一篇帖子中的点赞创建的帖子实际上会使用数据库中的点赞创建。

之前的问题是我忘记在子组件上放置一个 Key 属性,因此它不想更新,并且在数组上执行 slice() 也可以解决问题。

但是现在发生了什么??? AddScreen 中的 this.state.post 怎么知道上次点赞的帖子? 它不依赖于任何东西,它是一个完全独立的屏幕,没有指向 redux 状态或任何其他道具的链接.它只发生在喜欢上。描述、图片和 cmets 正确显示。

请帮助我,因为我正在失去理智,我花了这么多天的时间,在工作一周后它就像一场噩梦一样回来了。我已经尝试了很多东西(到处都提供关键道具,redux 状态的不同返回,在 Component 和 useEffect 中呈现的不同方法......)。我希望你能来救援!

一些图片:

1st post appears in the feed

post gets 3 likes

create 2nd post

Second posts is created with the same amount of likes as the previous one

I liked the 1st post 2 times and the last post 2 times, so the last post gets 3+2+2 likes

这里是代码,为了可读性,我删除了一些不重要的行。你可以在这里看到完整的代码:https://github.com/ginold/instagramCloneReactNative

添加帖子屏幕

    export class AddScreen extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          post: {
            author: '', createdAt: null, description: '',
            location: {}, likes: { total: 0 }, comments: [],
            pictures: []
          }
        }
        this.defaultPost = this.state.post
        this._addPost = this._addPost.bind(this)
      }
      _addPost() {
        this.props.navigation.navigate('Main', { uploading: true })
        PostApiService.addPost(this.state.post)
        this.setState({ post: this.defaultPost })
        console.log(JSON.stringify(this.state.post)) // even here the newly created post will have post.likes same as previous one!
      }

      render() {
        const { pictures } = this.state.post;

        return (

          <SafeAreaView style={{ flex: 1 }}>
            <ScrollView
              contentContainerStyle={styles.container}
              keyboardShouldPersistTaps='handled'>
              <Button>Next</Button>

              <Layout>
                <Text>Add a caption</Text>
                <Input
                  multiline={true}
                  numberOfLines={4}
                  iconResult={<Icon name='home-outline' size={25} />}
                  placeholder={'write something...'}
                  onChangeText={(text) => {
                    const post = this.state.post
                    this.setState({ post: { ...post, description: text } })
                  }}
                  value={this.state.post.description}>
                </Input>
              </Layout>
              <Button onPress={this._addPost}>SHARE</Button>
            </ScrollView>
          </SafeAreaView >
        );
      }
    };

后减速器

    if (action.type === "ADD_LIKE") {
      const postId = action.payload
      let posts = state.allPosts
      posts.map(post => {
        if (post.id === postId) {
          return { ...post, likes: { total: post.likes.total += 1 } }
        }
        return post
      })
      return { ...state, allPosts: posts.slice() } // quick fix for props not re-rendering in the feed
    }
    if (action.type === "SET_POSTS") {

      return { ...state, allPosts: action.payload }
    }
    if (action.type === "ADD_POST") {
      const post = action.payload // post object
      const posts = state.allPosts
      return { ...state, allPosts: [post, ...state.allPosts] }
    }
    return state

Post Actions = 喜欢的地方,Post 组件的子项

    class PostActions extends React.Component {
      constructor(props) {
        super(props)
        this.state = { post: this.props.post }
        this.size = 32
        this.addLike = this.addLike.bind(this)
      }
      addLike() {
        PostService.addLike(this.props.post)
        PostsReduxService.addLike(this.state.post.id)
      };
      render() {
        const { post } = this.state
        return (
            <Layout style={styles.heartIcon} key={`${ post.id } -heart`}>
              <Text key={`${ post.id } -likes`}>{`${ post.likes.total } likes`}  </Text>
              <TouchableOpacity onPress={this.addLike}>
                <Icon name={post.likes.total > 0 ? 'heart' : 'heart-outline'} width={this.size} height={this.size} fill='red' />
              </TouchableOpacity>
            </Layout>
          </Layout>
        )
      }
    }

带有 Post 组件的 Post List,连接到 mapStateToProps


    const PostList = (props) => {
        const [posts, setPosts] = React.useState([])

        React.useEffect(() => {
            if (props.posts.length === 0) {
                PostApiService.getPosts().then((posts) => {
                    PostsReduxService.setPosts(posts)
                    setPosts(posts)
                })
            }
            if (posts.length !== props.posts.length) {
                setPosts(props.posts)
            }
        }, [props.posts])


        const renderItem = ({ item, index }) => (
            <Layout style={styles.listItem} key={`${ item.id } -list - item`}>
                {/* causes an error in the console, it's a known bug in ui-kitten */}
                <Post key={`${ item.id }-post`} item={item} />
            </Layout>
        );
        return (
            (posts && !!posts.length && !refreshing)
                ? <List >}
                    style={styles.list} data={posts} renderItem={renderItem} />
                : <ActivityIndicator style={styles.loading} size="large" color="#0000ff" />

        )

create 1st post

【问题讨论】:

    标签: reactjs react-native redux state native


    【解决方案1】:

    这里有几件事:

    1. Post,为什么只是将item复制到state中,可以简单地使用从props传递来的post。所以整个状态,useEffect 逻辑可以被丢弃。这可能会解决问题。

    2. 这也将向下移动PostActions,并且应该显示正确的点赞数。

    3. PostActions 中,您同时使用帖子的副本和来自道具的帖子,但由于您从不更新状态,您只会更新第一个传递给它:this.state = { post: this.props.post }PostService.addLike(this.props.post) 和这里再次声明PostsReduxService.addLike(this.state.post.id)。再次,从状态中删除帖子的保存,并从道具中处理项目。

    还要查看 redux 的 mapDispatchToProps 而不是您的 PostsReduxService

    总而言之,您可以使用多种真实来源。 您将帖子保存在本地组件状态中,但也将它们保存到 redux。您应该决定将其保存在一个位置并坚持下去。

    【讨论】:

    • 您好,感谢您的回答。事实上,删除 useEffect 逻辑并仅使用 props 会产生相同的效果,因此至少代码更清晰了几行。至于 PostReduxService :这是我调用 myStore.dispatch(action) 的地方,所以从技术上讲它与 mapDispatchToProps 相同,或者是吗?我很确定我只有一个事实来源,但我会调查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 1970-01-01
    相关资源
    最近更新 更多