I am trying to make a list of messages and update it as I add more, I think I'm missing something but can't tell what it is.
App has 2 components - Messages and SendMessage, Messages is mapping over an array of Message Component. SenMessage has a form that will update the array store in messages state.
Thanks for any help in advance.
App.js
function App() {
const [messages, setMessages] = useState([{name: 'ken', 'message': "hayyy"},{name: 'kendra', 'message': "hayyy"}])
const handleSend = (message) => {
const newMessages = [...messages];
newMessages.push(message);
setMessages(newMessages);
console.log(message)
}
return (
<div className="App">
<Messages messages={messages} />
<SendMessage onSend={handleSend}/>
</div>
);
}
export default App;
Messages.js
const Messages = (props) => {
const messages = props.messages.map((message, index) => {
return (
<Message
key={index}
name={message.name}
message={message.message}
/>
)})
return (
<div>
{messages}
</div>
)}
export default Messages;
Message.js
const Message = (props) => {
return (
<div className="Message">
<p className="message">{props.message}</p>
<p className="name">{props.name}</p>
</div>
)}
export default Message;
SendMessage.js
const SendMessage = (props) => {
const [inputMessage, setInputMessage] = useState('')
const handleSubmit = (event) => {
event.preventDefault();
props.onSend(inputMessage);
setInputMessage('')
}
const handleChange = (event) => {
setInputMessage(event.target.value)
}
return (
<div className="SendMessage">
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="enter message"
value={inputMessage}
onChange={handleChange}
/>
<button>Send</button>
</form>
</div>
)}
export default SendMessage;
The main issue that I see here is that in the SendMessage
component, you are saving the state to a string and trying to send to a handleSend
function which expects an object with keys like name
and message
.
Thus you can update your handleSend
function like this:
const handleSend = (message) => {
const formattedMsg = { name: 'Some Name', message };
const newMessages = [...messages, formattedMsg];
setMessages(newMessages);
}
Also as a general practice use optional chaining whenever you are trying to use nested keys from objects. If you were using TypeScript, then this problem wouldn't occur in the first place since most probably you'd annotate the args with specific types. But here what we can do is atleast provide an optional chain(using ?
operator) and handle the case where no messages exists.
const messages = props.messages.map((message, index) => (
<Message
key={index}
name={message?.name}
message={message?.message}
/>
));
if (!messages) {
return (
<p>No messages...</p>
)
}
[Edit] I now see that @DrewReese has commented a similar answer. Didn't see it before posting.