开发者问题收集

为什么会发生这种情况?:TypeError:无法读取 REACT 中未定义的属性“用户名”

2021-03-20
1999

我正在尝试在 React 中创建一个 Messenger 克隆应用程序,但我真的不知道发生了什么事情导致了这个错误:

TypeError: Cannot read property 'username' of undefined

为什么突然出现这个错误?

请看一下!

所以我有两个文件,第一个是 App.js

import React, { useState, useEffect } from "react";
import { Button, InputLabel, Input, FormControl } from "@material-ui/core";
import "./App.css";
import Message from "./Message";
import db from "./firebase";
import firebase from "firebase";
import FlipMove from "react-flip-move";

function App() {
  const [input, setInput] = useState("");
  const [messages, setMessages] = useState([{}]);
  const [username, setUsername] = useState("");

  useEffect(() => {
    db.collection("messages")
      .orderBy("timestamp", "desc")
      .onSnapshot((snapshot) => {
        setMessages(
          snapshot.docs.map((doc) => ({ id: doc.data, message: doc.data() }))
        );
      });
  }, []);

  useEffect(() => {
    setUsername(prompt("please enter your name"));
  }, []);

  const sendMessage = (event) => {
    event.preventDefault();
    db.collection("messages").add({
      message: input,
      username: username,
      timestamp: firebase.firestore.FieldValue.serverTimestamp(),
    });
    setInput("");
  };

  return (
    <div className="App">
      <h1>Hello</h1>
      <h2>welcome {username}</h2>
      <form className="send">
        <FormControl>
          <InputLabel>Enter a message..</InputLabel>
          <Input
            value={input}
            onChange={(event) => setInput(event.target.value)}
          />
          <Button
            disabled={!input}
            variant="contained"
            color="primary"
            type="submit"
            onClick={sendMessage}
          >
            Send Message
          </Button>
        </FormControl>
      </form>

      <FlipMove>
        {messages.map(({ id, message }) => (
          <Message key={id} username={username} message={message} />
        ))}
      </FlipMove>
    </div>
  );
}

export default App;

第二个是 Message.js ,错误发生在其中:

import { Card, CardContent, Typography } from "@material-ui/core";
import React, { forwardRef } from "react";
import "./Message.css";

const Message = forwardRef(({ message, username }, ref) => {
  const isUser = username === message.username;
  return (
    <div ref={ref} className={`message ${isUser && "message_user"}`}>
      <Card className={isUser ? "message_userCard" : "message_guestCard"}>
        <CardContent>
          <Typography color="white" variant="h5" component="h2">
            {message.username}: {message.message}
          </Typography>
        </CardContent>
      </Card>
    </div>
  );
});

export default Message;

错误在这行 const isUser = username === message.username;

1个回答

这意味着作为 prop 传递给 Message 组件的 message 值是未定义的。

因此,当您在此处迭代消息时, messages 数组中至少有一个对象的 message 键没有定义值:

<FlipMove>
        {messages.map(({ id, message }) => (
          <Message key={id} username={username} message={message} />
        ))}
      </FlipMove>

尝试在 render() 函数之前打印出整个 messages 数组并检查存在哪些值。

尝试更改此行:

const [messages, setMessages] = useState([{}]);

更改为:

const [messages, setMessages] = useState([]);

编辑:问题在于以下这一行意味着您正在将 messages 数组初始化为: [{}] :

const [messages, setMessages] = useState([{}]);

这意味着您的数组中有一个元素,即一个空对象 {}。 它会一直保持这种状态,直到您的数据库读取完成并用您的真实数据填充您的数组。所以第一次,您的渲染函数将尝试理解这个只有这一个空对象的数组。

因此,当您像这样迭代它时:

{messages.map(({ id, message }) => (
          <Message key={id} username={username} message={message} />
        ))}

然后对于每个元素,由于这个解构赋值(如果您不确定那是什么,请查找该术语),它将查找 idmessage 属性:

({ id, message })

因此,由于您从数组中的一个空对象元素开始,它将查找该空对象的 .message 属性,但该属性不存在。它将是 undefined 。此 undefined 将作为 prop 传递给您的 Message 组件。然后在您的 Message 组件中,此行:

const isUser = username === message.username;

尝试访问 undefined 上的 .username 属性,因为请记住, message = undefined ,因为这是您无意中作为 prop 传递的。这就是为什么错误抱怨它在 undefined 上找不到 username 属性的原因:

TypeError: Cannot read property 'username' of undefined
heymoo
2021-03-20