在 React Native 中使用 forceUpdate() 时,嵌套 Map 函数不会更新状态

时间:2021-05-10 09:59:44

标签: javascript reactjs react-native react-navigation

我有一个复杂的数组填充对象。(如下所示)

 const privateMessages = Array [
  Object {
    "_id": "607533d511a2301b204720ed",
    "chat": Array [
      Object {
        "_id": "6098ffd30a2f4287f92be018",
        "createdAt": "2021-05-10T09:41:39.683Z",
        "text": "G",
        "user": Object {
          "_id": "60716a38136f970ba4a0526e",
        },
      },
      Object {
        "_id": "6097b6e69f98cbf5ba6deaf8",
        "createdAt": "2021-05-09T10:18:36.972Z",
        "text": "ত",
        "user": Object {
          "_id": "60716f7cf3a75846ee1f5d38",
        },
      },
      Object {
        "_id": "6097b6aacd62683ba317965d",
        "createdAt": "2021-05-09T10:17:36.182Z",
        "text": "H",
        "user": Object {
          "_id": "60716a38136f970ba4a0526e",
        },
      }
    ],
    "pair": Array [
      Object {
        "_id": "60716a38136f970ba4a0526e",
        "firstName": "Sayan",
        "lastName": "Biswas",
      },
    ],
  },
]

使用 setState hook 更新它非常困难,所以我决定使用 force Update 重新渲染组件,但它不起作用。 我更新状态的方式如下

privateMessages.forEach((i) => {
                    if (i.pair[0]._id == data.sender) {
                        i.chat.unshift(data.chatObj)
                    }
                })

这是我正在使用的 forceUpdate 钩子

function useForceUpdate() {
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => value + 1); // update the state to force render
}

我的称呼方式

const forceUpdate = useForceUpdate()

我在项目的其他部分使用了相同的 forceUpdate() 钩子并且它正常工作,但我不知道为什么它不能与下面给出的嵌套地图函数一起使用

编辑:-

许多答案告诉我不要使用 forceUpdate 所以我删除了它们。 我尝试了答案中给出的所有解决方案,但都没有奏效。从@Punisher 的答案中获得灵感,我自己制定了状态更新部分的解决方案,但应用程序在运行时崩溃。

socket.on("recieve-private-message", (data) => {
                setPrivateMessages(prevState => {
                    const privateMessagesCopy = JSON.parse(JSON.stringify(prevState))
                    privateMessagesCopy.forEach((i) => {
                        if (i.pair[0]._id == data.sender) {
                            i.chat.unshift(data.chatObj)
                        }
                    })
                    return privateMessagesCopy
                }                    
                )
            })

整个代码:-

import React, { useState, useEffect, useContext } from 'react';
import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
import AsyncStorage from "@react-native-async-storage/async-storage"
import API from '../api.js'
import { useNavigation } from '@react-navigation/native';
import { SocketObj } from "./Main"

function useForceUpdate() {
    const [value, setValue] = useState(0); // integer state
    return () => setValue(value => value + 1); // update the state to force render
}

const ChatScreen = () => {

    const navigation = useNavigation()

    let socket = useContext(SocketObj)

    let [privateMessages, setPrivateMessages] = useState([])

    let [userId, setUserId] = useState('')

    const forceUpdate = useForceUpdate()

    useEffect(
        () => {
            const fetchData = async () => {
                try {
                    const response = await API.get('get/chats', {
                        headers: {
                            'Content-Type': 'application/json',
                            "auth-token": await AsyncStorage.getItem("token")
                        }
                    })
                    setPrivateMessages(response.data.chatFriends)
                    setUserId(response.data.userId)
                } catch (err) {
                    console.log(err.response)
                }
            }
            fetchData()

            socket.on("recieve-private-message", (data) => {
                privateMessages.forEach((i) => {
                    if (i.pair[0]._id == data.sender) {
                        i.chat.unshift(data.chatObj)
                    }
                })
                forceUpdate()
            })
        }, []
    )


    useEffect(
        () => {
            console.log("changed")
        },[privateMessages]
    )

    return (<View>
        <ScrollView >
            {
                privateMessages.map(
                    (i) => i.pair.map(
                        (j) => {
                            return (
                                <>
                                    <TouchableOpacity
                                        key={j._id}
                                        onPress={() => {
                                            navigation.navigate("PrivateConversation", {
                                                chats: i.chat,
                                                userId: userId,
                                                socket: socket,
                                                name: j.firstName,
                                                recieverId: j._id
                                            })
                                        }
                                        } >
                                        <Text key={j._id} >{j.firstName + ' ' + j.lastName}</Text>
                                    </TouchableOpacity>
                                </>
                            )
                        }
                    )
                )
            }
        </ScrollView>
    </View>)
}

export default ChatScreen

3 个答案:

答案 0 :(得分:0)

我认为您没有在函数中更新状态

尝试以下操作:-

socket.on("recieve-private-message", (data) => {
  const privateMessagesCopy = [...privateMessages]
  const updatedPrivateMessages = privateMessagesCopy.map((i) => {
    if (i.pair[0]._id == data.sender) {
      i.chat.unshift(data.chatObj)
    }
    return i;
  })
  setPrivateMessage([...updatedPrivateMessages]);
})

答案 1 :(得分:0)

我会尽可能避免强制更新模式。我不认为你在这里需要它。虽然我看不出有什么明显的错误,但我建议您尝试这两个选项来帮助调试。如果这些解决方案不起作用,则说明还有其他问题。

(1) 使用 setState 代替。更新聊天对象时,请先创建它的深层副本。使用当前方法更新深层副本,然后调用 setState(copy)。注意:确保使用库进行深度复制,如 lodash 或 stringify 技巧 (What is the most efficient way to deep clone an object in JavaScript?)

(2) 改用减速器。当你有像你这样的复杂对象时,reducer 是非常常用的。这可能是最佳实践(可维护性和可读性)方面的最佳解决方案

答案 2 :(得分:0)

将您的套接字函数更改为:

socket.on("recieve-private-message", (data) => {
  setPrivateMessages(prevState => prevState
     .map(privateMessage => {
        const [firstPair] = privateMessage.pair

        return firstPair._id !== data.sender
            ? privateMessage
            : ({
                ...privateMessage,
                chat: [
                    data.chatObj,
                    ...privateMessage.chat
                ]
            })
     })
  )
})
相关问题