无法读取未定义的 属性 'map' - React Custom Hooks / useContext 一个有效/一个无效
Cannot read property 'map' of undefined - React Custom Hooks / useContext one works / one doesn't
我目前正在关注 youtube 上的教程,使用 react 和来自 webDevSimplified 的 socket.io 构建 whatsapp 克隆:https://www.youtube.com/watch?v=tBr-PybP_9c
这里是主要的回购协议:'https://github.com/WebDevSimplified/Whatsapp-Clone/tree/master/client
由于某种原因我的自定义 useConversation
钩子 return 未定义而我的 useContacts
钩子可以正常工作。
设置如下:
App.js :
import Dashboard from "./Dashboard";
import { ContactsProvider } from "../contexts/ContactsProvider";
import { ConversationsProvider } from "../contexts/ConversationsProvider";
import Test from "../components/test";///test
console.log(Test)//test purpose
function App() {
const [id, setId] = useLocalStorage("id");
const dashboard = (
<ContactsProvider>
<ConversationsProvider id={id}>
<Dashboard id={id} />
</ConversationsProvider>
</ContactsProvider>
);
return id ? dashboard : <Login onIdSubmit={setId} />;
}
export default App;
ContactsProvider.js
import React, { useContext } from "react";
import useLocalStorage from "../hooks/useLocalStorage";
const ContactsContext = React.createContext();
export function useContacts() {
return useContext(ContactsContext);
}
export function ContactsProvider({ children }) {
const [contacts, setContacts] = useLocalStorage("contacts", []);//initalValue an empty array
function createContact(id, name) {
setContacts((prevContacts) => {
return [...prevContacts, { id, name }];
});
}
return (
<ContactsContext.Provider value={{ contacts, createContact }}>
{children}
</ContactsContext.Provider>
);
}
Contacts.js - 这里是我的 useContacts
作品
import React from "react";
import { ListGroup } from "react-bootstrap";
import { useContacts } from "../contexts/ContactsProvider";
export default function Contacts() {
const { contacts } = useContacts();
console.log(`contacts: ${contacts}`); //returns object, object as expected
return (
<ListGroup variant="flush">
{contacts.map((contact) => (//visibly working in UI when commenting out the ListGroup in conversations.js
<ListGroup.Item key={contact.id}>{contact.name}</ListGroup.Item>
))}
</ListGroup>
);
}
这里是有问题的部分:
ConversationsProvider.js
import React, { useContext } from "react";
import useLocalStorage from "../hooks/useLocalStorage";
import { useContacts } from "./ContactsProvider";
const ConversationsContext = React.createContext();
export function useConversations() {
return useContext(ConversationsContext);
}
export function ConversationsProvider({ children }) {
const [conversations, setConversations] = useLocalStorage(
"conversations", []);//as well empty array
const { contacts } = useContacts();
function createConversation(recipients) {
setConversations((prevConversations) => {
return [...prevConversations, { recipients, messages: [] }];
});
}
const formattedConversations = conversations.map((conversation) => {
const recipients = conversation.recipients.map((recipient) => {
const contact = contacts.find((contact) => {
return contact.id === recipient;
});
const name = (contact && contact.name) || recipient;
return { id: recipient, name };
});
return { ...conversation, recipients };
});
const value = {
conversations: formattedConversations,
createConversation,
};
return (
<ConversationsContext.Provider value={{ value }}>
{children}
</ConversationsContext.Provider>
);
}
以及导致错误的组件:
Conversations.js:
import React from "react";
import { ListGroup } from "react-bootstrap";
import { useConversations } from "../contexts/ConversationsProvider";
export default function Conversations() {
const { conversations } = useConversations();
console.log( `conversations: ${conversations}`)//returns undefined
return (
<ListGroup variant="flush">
{conversations.map((conversation, index) => (//can't map because conversations is undefined
<ListGroup.Item key={index}>
{conversation.recipients
.map(r => r.name)
.join(", ")}
</ListGroup.Item>
))}
</ListGroup>
);
}
为清楚起见,这里是 localStorage 设置:
import { useEffect, useState } from 'react'
const PREFIX = 'whatsapp-clone-'
export default function useLocalStorage(key, initialValue) {
const prefixedKey = PREFIX + key;
const [value, setValue] = useState(() => {
const jsonValue = localStorage.getItem(prefixedKey);
if (jsonValue != null) return JSON.parse(jsonValue);
if (typeof initialValue === "function") {
return initialValue();
} else {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(prefixedKey, JSON.stringify(value));
}, [prefixedKey, value]);
return [value, setValue];
}
几个小时以来,我一直在尝试解决这个问题,但 运行 毫无想法。我设置了一个 test.js 并在 Test.js 函数中导入了钩子。 return 分别是它们的对象。
我使用 npx create-react-app 创建了应用程序,运行 通过 yarn 创建了应用程序。
问题出在你的ConversationsProvider.js
:
const value = {
conversations: formattedConversations,
createConversation,
};
return (
<ConversationsContext.Provider value={{ value }}>
{children}
</ConversationsContext.Provider>
);
下面几行都是一样的:
<ConversationsContext.Provider value={{ value }}>
<ConversationsContext.Provider value={{ value: value }}>
<ConversationsContext.Provider value={{ value: { conversations: formattedConversations, createConversation: createConversation } }}>
当你执行:
const { conversations } = useConversations();
conversations
将被设置为 undefined
因为返回的对象将只有 属性 value
.
要解决此问题,请更改以下行以移除嵌套:
<ConversationsContext.Provider value={{ value }}>
// to
<ConversationsContext.Provider value={value}>
PS。这里有一个技巧可以提高你的调试技巧。你已经这样做了:
const { conversations } = useConversations();
console.log(conversations);
记录了 undefined
。下一步是不立即销毁对象,而是记录整个上下文值。
const contextValue = useConversations();
console.log(contextValue);
这表明 useConversations
返回的对象不是您期望的那样。
我目前正在关注 youtube 上的教程,使用 react 和来自 webDevSimplified 的 socket.io 构建 whatsapp 克隆:https://www.youtube.com/watch?v=tBr-PybP_9c
这里是主要的回购协议:'https://github.com/WebDevSimplified/Whatsapp-Clone/tree/master/client
由于某种原因我的自定义 useConversation
钩子 return 未定义而我的 useContacts
钩子可以正常工作。
设置如下:
App.js :
import Dashboard from "./Dashboard";
import { ContactsProvider } from "../contexts/ContactsProvider";
import { ConversationsProvider } from "../contexts/ConversationsProvider";
import Test from "../components/test";///test
console.log(Test)//test purpose
function App() {
const [id, setId] = useLocalStorage("id");
const dashboard = (
<ContactsProvider>
<ConversationsProvider id={id}>
<Dashboard id={id} />
</ConversationsProvider>
</ContactsProvider>
);
return id ? dashboard : <Login onIdSubmit={setId} />;
}
export default App;
ContactsProvider.js
import React, { useContext } from "react";
import useLocalStorage from "../hooks/useLocalStorage";
const ContactsContext = React.createContext();
export function useContacts() {
return useContext(ContactsContext);
}
export function ContactsProvider({ children }) {
const [contacts, setContacts] = useLocalStorage("contacts", []);//initalValue an empty array
function createContact(id, name) {
setContacts((prevContacts) => {
return [...prevContacts, { id, name }];
});
}
return (
<ContactsContext.Provider value={{ contacts, createContact }}>
{children}
</ContactsContext.Provider>
);
}
Contacts.js - 这里是我的 useContacts
作品
import React from "react";
import { ListGroup } from "react-bootstrap";
import { useContacts } from "../contexts/ContactsProvider";
export default function Contacts() {
const { contacts } = useContacts();
console.log(`contacts: ${contacts}`); //returns object, object as expected
return (
<ListGroup variant="flush">
{contacts.map((contact) => (//visibly working in UI when commenting out the ListGroup in conversations.js
<ListGroup.Item key={contact.id}>{contact.name}</ListGroup.Item>
))}
</ListGroup>
);
}
这里是有问题的部分:
ConversationsProvider.js
import React, { useContext } from "react";
import useLocalStorage from "../hooks/useLocalStorage";
import { useContacts } from "./ContactsProvider";
const ConversationsContext = React.createContext();
export function useConversations() {
return useContext(ConversationsContext);
}
export function ConversationsProvider({ children }) {
const [conversations, setConversations] = useLocalStorage(
"conversations", []);//as well empty array
const { contacts } = useContacts();
function createConversation(recipients) {
setConversations((prevConversations) => {
return [...prevConversations, { recipients, messages: [] }];
});
}
const formattedConversations = conversations.map((conversation) => {
const recipients = conversation.recipients.map((recipient) => {
const contact = contacts.find((contact) => {
return contact.id === recipient;
});
const name = (contact && contact.name) || recipient;
return { id: recipient, name };
});
return { ...conversation, recipients };
});
const value = {
conversations: formattedConversations,
createConversation,
};
return (
<ConversationsContext.Provider value={{ value }}>
{children}
</ConversationsContext.Provider>
);
}
以及导致错误的组件:
Conversations.js:
import React from "react";
import { ListGroup } from "react-bootstrap";
import { useConversations } from "../contexts/ConversationsProvider";
export default function Conversations() {
const { conversations } = useConversations();
console.log( `conversations: ${conversations}`)//returns undefined
return (
<ListGroup variant="flush">
{conversations.map((conversation, index) => (//can't map because conversations is undefined
<ListGroup.Item key={index}>
{conversation.recipients
.map(r => r.name)
.join(", ")}
</ListGroup.Item>
))}
</ListGroup>
);
}
为清楚起见,这里是 localStorage 设置:
import { useEffect, useState } from 'react'
const PREFIX = 'whatsapp-clone-'
export default function useLocalStorage(key, initialValue) {
const prefixedKey = PREFIX + key;
const [value, setValue] = useState(() => {
const jsonValue = localStorage.getItem(prefixedKey);
if (jsonValue != null) return JSON.parse(jsonValue);
if (typeof initialValue === "function") {
return initialValue();
} else {
return initialValue;
}
});
useEffect(() => {
localStorage.setItem(prefixedKey, JSON.stringify(value));
}, [prefixedKey, value]);
return [value, setValue];
}
几个小时以来,我一直在尝试解决这个问题,但 运行 毫无想法。我设置了一个 test.js 并在 Test.js 函数中导入了钩子。 return 分别是它们的对象。
我使用 npx create-react-app 创建了应用程序,运行 通过 yarn 创建了应用程序。
问题出在你的ConversationsProvider.js
:
const value = {
conversations: formattedConversations,
createConversation,
};
return (
<ConversationsContext.Provider value={{ value }}>
{children}
</ConversationsContext.Provider>
);
下面几行都是一样的:
<ConversationsContext.Provider value={{ value }}>
<ConversationsContext.Provider value={{ value: value }}>
<ConversationsContext.Provider value={{ value: { conversations: formattedConversations, createConversation: createConversation } }}>
当你执行:
const { conversations } = useConversations();
conversations
将被设置为 undefined
因为返回的对象将只有 属性 value
.
要解决此问题,请更改以下行以移除嵌套:
<ConversationsContext.Provider value={{ value }}>
// to
<ConversationsContext.Provider value={value}>
PS。这里有一个技巧可以提高你的调试技巧。你已经这样做了:
const { conversations } = useConversations();
console.log(conversations);
记录了 undefined
。下一步是不立即销毁对象,而是记录整个上下文值。
const contextValue = useConversations();
console.log(contextValue);
这表明 useConversations
返回的对象不是您期望的那样。