Redux / React Native State получает значения из предыдущих состояний и неправильно обновляет / перерисовывает - PullRequest
0 голосов
/ 14 апреля 2020

Здесь происходит так много странных вещей, что я не знаю, с чего начать. Самое смешное, что раньше он работал нормально и внезапно останавливался.

Это поток:

  1. screens/Add.js => Я создаю объект post в State, pass это к моему PostAPI => firebase => добавить в магазин приставки => показать в FeedScreen.
  2. Перенаправить на screens/feed.js. Пост появляется через несколько секунд. До сих пор все идет хорошо.
  3. Если мне нравится пост, он увеличивает post.likes.total на единицу. Я ищу его по идентификатору в хранилище приставок и обновляю массив => new state отображает список сообщений, который получает сообщения через mapState ToProps. Изменения выглядят так, как и ожидалось.
  4. Теперь я создаю новый пост ... он идет так же, как и выше.
  5. Новый пост получает столько же лайков, что и предыдущий Я только что нажал! И все будущие посты получают такое же количество предыдущих лайков и ТАКЖЕ ОБНОВЛЯЮТСЯ, когда я нажимаю на ПРЕДВАРИТЕЛЬНО созданные посты. При нажатии на только что созданный, он обновляет только себя. Нажимая на предыдущее, он обновляет себя и следующее. Нажатие на 3-й пост обновит себя, а следующие 2 и т. Д.
  6. Если я перезагрузлю страницу, лайки будут корректно загружены из БД, но пост, созданный с лайками из предыдущего поста, фактически будет созданный с такими лайками в БД.

Раньше проблема была в том, что я забыл поместить свойство Key в дочерний компонент, и поэтому оно не хотело обновляться, и сделал slice () для Массив сделал свое дело также.

Но что сейчас происходит ??? Как даже this.state.post в AddScreen знает о лайках последнего понравившегося поста? Это не зависит от чего-либо, это совершенно отдельный экран без ссылки на состояние притока или каких-либо других подпорок. И это происходит только с лайками. Описание, фотографии и комментарии отображаются правильно.

Пожалуйста, помогите мне, потому что я схожу с ума, я потратил на это столько дней, и он вернулся, как кошмар, после работы в течение недели. Я перепробовал так много вещей (везде давал ключевые реквизиты, разную отдачу от избыточного состояния, разные подходы рендеринга в Component и useEffect ...). Я надеюсь, что вы пришли со спасением!

Некоторые фотографии:

1-й пост появляется в ленте

сообщение получает 3 лайка

создать 2-е сообщение

Второе сообщение создано с таким же количеством лайков, как и у предыдущего

Мне понравился 1-й пост 2 раза, а последний пост 2 раза, поэтому последний пост получает 3 + 2 + 2 лайка

Вот код, я удалил несколько неважных строк ради читабельности , Вы можете увидеть полный код здесь: 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 >
        );
      }
    };

Post Reducer

    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

Действия сообщения = где есть лайки, дочерний элемент компонента

    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>
        )
      }
    }

Список сообщений с компонентами сообщений, подключенных к 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" />

        )

создать 1-е сообщение

1 Ответ

0 голосов
/ 14 апреля 2020

Итак, несколько вещей здесь:

  1. В Post, почему вы просто копируете элемент в состояние, вы можете просто использовать сообщение, переданное из реквизита. Таким образом, все состояние useEffect logi c может быть отброшено. Это могло бы прояснить ситуацию.

  2. Это также пройдет вниз PostActions, и должно быть показано правильное подобное число.

  3. In PostActions, вы работаете как с копией поста, так и с постом из реквизита, но так как вы никогда не обновляете состояние, вы обновите только первый проход к нему: this.state = { post: this.props.post }, но PostService.addLike(this.props.post) и здесь снова состояние PostsReduxService.addLike(this.state.post.id). Опять же, удалите сохранение поста из состояния и просто обработайте элемент из реквизита.

Также посмотрите на mapDispatchToProps redux вместо вашего PostsReduxService.

В общем, вы работаете с несколькими источниками правды. Вы сохраняете сообщение в своем локальном состоянии компонента, но также сохраняете его в редуксе. Вы должны выбрать одно место, где его сохранить, и придерживаться этого.

...