我遵循本教程构建WhatsApp克隆,但我使用的是最新版本的React和React路由器dom,
每当我开始新的对话时,它都应该呈现这个组件,而不是那个,它什么都不呈现。
OpenConversation.js
import React, { useState, useCallback } from 'react'
import { Form, InputGroup, Button } from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider';
export default function OpenConversation() {
const [text, setText] = useState('')
const setRef = useCallback(node => {
if (node) {
node.scrollIntoView({ smooth: true })
}
}, [])
const { sendMessage, selectedConversation } = useConversations()
function handleSubmit(e) {
e.preventDefault()
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message, index) => {
const lastMessage = selectedConversation.messages.length - 1 === index
return (
<div
ref={lastMessage ? setRef : null}
key={index}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form onSubmit={handleSubmit}>
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={e => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<InputGroup.Append>
<Button type="submit">Send</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
该组件在Dashboard.js
上呈现
import React, { useState, useCallback } from 'react'
import { Form, InputGroup, Button } from 'react-bootstrap'
import { useConversations } from '../contexts/ConversationsProvider';
export default function OpenConversation() {
const [text, setText] = useState('')
const setRef = useCallback(node => {
if (node) {
node.scrollIntoView({ smooth: true })
}
}, [])
const { sendMessage, selectedConversation } = useConversations()
function handleSubmit(e) {
e.preventDefault()
sendMessage(
selectedConversation.recipients.map(r => r.id),
text
)
setText('')
}
return (
<div className="d-flex flex-column flex-grow-1">
<div className="flex-grow-1 overflow-auto">
<div className="d-flex flex-column align-items-start justify-content-end px-3">
{selectedConversation.messages.map((message, index) => {
const lastMessage = selectedConversation.messages.length - 1 === index
return (
<div
ref={lastMessage ? setRef : null}
key={index}
className={`my-1 d-flex flex-column ${message.fromMe ? 'align-self-end align-items-end' : 'align-items-start'}`}
>
<div
className={`rounded px-2 py-1 ${message.fromMe ? 'bg-primary text-white' : 'border'}`}>
{message.text}
</div>
<div className={`text-muted small ${message.fromMe ? 'text-right' : ''}`}>
{message.fromMe ? 'You' : message.senderName}
</div>
</div>
)
})}
</div>
</div>
<Form onSubmit={handleSubmit}>
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={e => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<InputGroup.Append>
<Button type="submit">Send</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
</Form>
</div>
)
}
App.js
import React from 'react'
import Login from './Login'
import useLocalStorage from '../hooks/useLocalStorage';
import Dashboard from './Dashboard'
import { ContactsProvider } from '../contexts/ContactsProvider'
import { ConversationsProvider } from '../contexts/ConversationsProvider';
import { SocketProvider } from '../contexts/SocketProvider';
import TopNavBar from './TopNavBar';
import Signup from "./Signup"
import { Container } from "react-bootstrap"
import { AuthProvider } from "../contexts/AuthContext"
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
import PrivateRoute from "./PrivateRoute"
import ForgotPassword from "./ForgotPassword"
import UpdateProfile from "./UpdateProfile"
function App() {
const [id, setId] = useLocalStorage('id', 0)
const AuthM = (
<AuthProvider>
<Router>
<TopNavBar />
<Routes>
<Route
path="/"
element={
<PrivateRoute>
<SocketProvider id={id}>
<ContactsProvider>
<ConversationsProvider id={id}>
<Dashboard id={id} />
</ConversationsProvider>
</ContactsProvider>
</SocketProvider>
</PrivateRoute>
}
>
</Route>
<Route
path="/update-profile"
element={
<PrivateRoute>
<UpdateProfile />
</PrivateRoute>
}
>
</Route>
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login onIdSubmit={setId} />} />
<Route path="/forgot-password" element={<ForgotPassword />} />
</Routes>
</Router>
</AuthProvider>
)
return (
AuthM
)
}
export default App;
当应用程序尝试渲染OpenConversation.js
时,我收到以下错误
组件中出现上述错误:在div在http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:42187:5在div在http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:4910:5形式在http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:45143:5在div在OpenConversation(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:1386:74(在div在仪表板(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:451:5(在ConversationsProvider(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3292:5(在ContactsProvider(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3181:5(在SocketProvider(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3498:5(在PrivateRoute(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:1572:5(在Routes(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:63406:5(在路由器(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:663339:15(在BrowserRouter(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:6819:5(在AuthProvider(http://localhost:3000/main.710ea063df9fff086c2a.hot-update.js:3032:5(在应用程序(http://localhost:3000/main.ae1831d77cead42fa1a1.hot-update.js:56:89(
和这个
未捕获错误:元素类型无效:应为字符串(用于内置组件(或类/函数(用于复合组件(,但得到:未定义。您可能忘记了从中定义的文件导出组件,或者您可能混淆了默认导入和命名导入。
检查OpenConversation
的渲染方法。
知道那里发生了什么吗?提前谢谢。
希望这对其他人有所帮助,根据@BrianThompsons的评论,我发现是<InputGroup.Append>
导致了错误。
我正在做完全相同的教程,也遇到了同样的问题(这已经不是我第一次在复制代码时出错了——自从视频发布以来,已经有了一些突破性的更新(。
不要使用<InputGroup.Append>
,只需将按钮插入InputGroup
即可,如下所示:
<Form.Group className="m-2">
<InputGroup>
<Form.Control
as="textarea"
required
value={text}
onChange={(e) => setText(e.target.value)}
style={{ height: '75px', resize: 'none' }}
/>
<Button type="submit">Send</Button>
</InputGroup>
</Form.Group>
这就把按钮放在了文本框旁边,正如我们所希望的那样。希望能有所帮助。