繁体   English   中英

嵌套 Map function 在使用 forceUpdate() 反应原生时不会更新 state

[英]Nested Map function doesnt update the state while using forceUpdate() in react native

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

 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 钩子更新它非常困难,所以我决定使用强制更新来重新渲染组件,但它不起作用。 下面给出了我更新 state 的方式

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() 钩子并且它工作正常,但我不知道为什么它不能与下面给出的嵌套 map function 一起工作

编辑:-

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

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

我认为您没有在 function 中更新 state

试试下面的东西: -

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) 改用 setState。 当您更新聊天 object 时,首先创建它的深层副本。 使用当前方法更新深层副本,然后调用 setState(copy)。 注意:确保使用库进行深度复制,如 lodash 或 stringify 技巧( 在 JavaScript 中深度克隆 object 的最有效方法是什么?

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

将您的插座 function 更改为:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM