我有一个复杂的数组填充对象。(如下所示)
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
答案 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
]
})
})
)
})