63055


## 概要

現在、React + Pusherでリアルタイムのチャット機能を実装していますが、jsxの部分で下記のエラーが発生しました。  
具体的には、取得した全メッセージの内容をjsx内で`map()`を使用して表示しているのですがそこでエラーが発生しています。  
自分なりに色々調べて`Array.from()`でオブジェクトを配列に変換しましたが、解決せず…。  
どなたか解決方法のご教授お願い致します。

＜Chat.get()でconsole.log()した結果＞  
`useEffect`内の`Chat.get()`で下記の様な、データベースに保存されたチャットの内容がバックエンドのLaravelから返ってきます。  
これをjsx内(`messageList`)で`Array.from(messages).map()`で回しています。

[code]

    {messages: Array(10)}
    messages: Array(10)
    0:
    id: 3
    board_id: "ldqc10ol"
    user_id: "a"
    message: "hello"
    created_at: "2020-02-14 09:16:27"
    updated_at: "2020-02-14 09:16:27"
    __proto__: Object
    1: {id: 4, board_id: "ldqc10ol", user_id: "a", message: "d", created_at: "2020-02-14 09:21:23", …}
    2: {id: 5, board_id: "ldqc10ol", user_id: "a", message: "l", created_at: "2020-02-14 09:28:25", …}
    3: {id: 6, board_id: "ldqc10ol", user_id: "a", message: "kkkk", created_at: "2020-02-14 09:38:07", …}
    4: {id: 7, board_id: "ldqc10ol", user_id: "a", message: "あ", created_at: "2020-02-14 09:56:05", …}
    5: {id: 8, board_id: "ldqc10ol", user_id: "a", message: "aaaaaa", created_at: "2020-02-14 10:05:55", …}
    6: {id: 9, board_id: "ldqc10ol", user_id: "a", message: "a", created_at: "2020-02-14 10:46:31", …}
    7: {id: 10, board_id: "ldqc10ol", user_id: "a", message: "a", created_at: "2020-02-14 10:47:22", …}
    8: {id: 11, board_id: "ldqc10ol", user_id: "a", message: "a", created_at: "2020-02-14 10:52:25", …}
    9: {id: 12, board_id: "ldqc10ol", user_id: "a", message: "a", created_at: "2020-02-14 10:53:46", …}
    length: 10
    __proto__: Array(0)
    __proto__: Object
    
[/code]

## エラーの内容

[code]

    Objects are not valid as a React child (found: object with keys {messageList}). If you meant to render a collection of children, use an array instead.
    
[/code]

## 該当のコード

[code]

    import React, { useEffect } from 'react'
    
    import { useDispatch, useSelector } from 'react-redux'
    
    import styled from 'styled-components'
    import Button from '@material-ui/core/Button'
    import IconButton from '@material-ui/core/IconButton'
    import Dialog from '@material-ui/core/Dialog'
    import DialogActions from '@material-ui/core/DialogActions'
    import DialogTitle from '@material-ui/core/DialogTitle'
    import Divider from '@material-ui/core/Divider'
    import TextsmsIcon from '@material-ui/icons/Textsms'
    import TelegramIcon from '@material-ui/icons/Telegram'
    
    import Chat from './../../../models/Chat'
    import User from './../../../models/User'
    import Board from './../../../models/Board'
    
    import Pusher from 'pusher-js'
    
    Pusher.logToConsole = true
    
    const pusher = new Pusher('*******', {
        cluster: 'ap3',
        forceTLS: true
    });
    
    const ChatDialog = props => {
        const { open, onClose, fullScreen } = props
        const [msg, setMsg] = React.useState('')
        const [messages, setMessages] = React.useState([])
        const userID = useSelector(state => state.UserReducer.userID)
        let isChanged = true
    
        useEffect(() => {
            const channelName = 'chat-' + Board.getBoardID()
            const channel = pusher.subscribe(channelName)
    
            channel.bind('App\\Events\\ChatMessageReceived', data => {
                setMessages([...messages, data])
            })
            return () => {
                channel.unbind('App\\Events\\ChatMessageReceived')
            }
        }, [setMessages, messages])
    
        useEffect(() => {
            const token = JSON.parse(User.get('token')).token
            const boardID = Board.getBoardID()
    
            if (token) {
                Chat.get(token, boardID)
                    .then(res => {
                        setMessages(res.data.messages)
                        console.log(res.data)
                    })
                    .catch(e => {
                        console.log(e)
                    })
            }
        }, [isChanged])
    
        const handleOnChangeMsg = e => {
            setMsg(e.target.value)
        }
    
        const handleSendMsg = () => {
            const token = JSON.parse(User.get('token')).token
            const boardID = Board.getBoardID()
    
            if (token) {
                Chat.send(token, boardID, msg)
                    .then(res => {
                        setMsg('')
                    })
                    .catch(e => {
                        console.log(e)
                    })
            }
        }
    
        let messageList = (
            Array.from(messages).map((msg, i) => (
                <React.Fragment key={i}>
                    {msg.user_id === userID ? <UserMsg>{msg[i]}</UserMsg> : <Msg>{msg[i]}</Msg>}
                </React.Fragment>
            ))
        )
    
        const fullDialog = (
            <Dialog
                fullScreen
                open={open}
                scroll="paper"
                aria-labelledby="alert-dialog-title"
                aria-describedby="alert-dialog-description"
            >
                <Flex>
                    <StyledDialogTitle><StyledTextsmsIcon /><Span>チャット</Span></StyledDialogTitle>
                    <StyledDialogActions>
                        <Button onClick={onClose} color="primary" autoFocus>
                            <Span>閉じる</Span>
                        </Button>
                    </StyledDialogActions>
                </Flex>
                <DialogContent>
                    <Textarea placeholder="メッセージを入力" onChange={handleOnChangeMsg} value={msg}></Textarea>
                    <StyledIconButton onClick={handleSendMsg}><StyledTelegramIcon /></StyledIconButton>
                </DialogContent>
                <MessageArea>
                    {messages.length === 0 ? <p>メッセージがありません</p> :
                        { messageList }
                    }
                </MessageArea>
            </Dialog >
        )
        const nonFullDialog = (
            <Dialog
                open={open}
                scroll="paper"
                fullWidth={true}
                maxWidth="sm"
                aria-labelledby="alert-dialog-title"
                aria-describedby="alert-dialog-description"
            >
                <Flex>
                    <StyledDialogTitle><StyledTextsmsIcon /><Span>チャット</Span></StyledDialogTitle>
                    <StyledDialogActions>
                        <Button onClick={onClose} color="primary" autoFocus>
                            <Span>閉じる</Span>
                        </Button>
                    </StyledDialogActions>
                </Flex>
                <DialogContent>
                    <Textarea placeholder="メッセージを入力" onChange={handleOnChangeMsg} value={msg}></Textarea>
                    <StyledIconButton onClick={handleSendMsg}><StyledTelegramIcon /></StyledIconButton>
                </DialogContent>
                <MessageArea>
                    {messages.length === 0 ? <p>メッセージがありません</p> :
                        { messageList }
                    }
                </MessageArea>
            </Dialog >
        )
    
        return (
            <>
                {fullScreen === true ? fullDialog : nonFullDialog}
            </>
        )
    }
    
    const Flex = styled.div`
        display: flex;
        justify-content: space-between;
        background-color: #224272;
    `
    const Textarea = styled.textarea`
        resize: none;
        width: 100%;
        height: 35px;
        border: 1px solid #224272;
    `
    const Span = styled.span`
        font-size: 0.9em;
        color: white;
    `
    
    const StyledDialogTitle = styled(DialogTitle)`
        color: white;
    `
    const DialogContent = styled.div`
        height: 45px;
        display: flex;
        justify-content: space-between;
        padding: 0;
        padding-left: 5px;
        padding-top: 5px;
    `
    const MessageArea = styled.div`
        height: 450px;
    `
    const StyledDialogActions = styled(DialogActions)`
    
    `
    const StyledIconButton = styled(IconButton)`
        vertical-align: middle;
        padding: 0 10px;
        height: 35px;
    `
    
    const StyledTextsmsIcon = styled(TextsmsIcon)`
        vertical-align: middle;
        margin-right: 3px;
    `
    const StyledTelegramIcon = styled(TelegramIcon)`
        vertical-align: middle;
        padding: 0;
    `
    
    const Msg = styled.p`
        width: 100%
        text-align: left;
    `
    const UserMsg = styled.p`
        width: 100%
        text-align: right;
    `
    
    export default ChatDialog
    
[/code]


CC BY-SA 4.0
2020-02-14T14:03:31.630
63054
2020-02-14T15:08:34.940
32711
question
javascript laravel reactjs
ReactのJSX内でmap()を使用した際のエラー


`messageList`の周りに余計な`{ }`があるのが原因です。

[code]

                {messages.length === 0 ? <p>メッセージがありません</p> :
                    { messageList }
                }
    
[/code]

このような箇所が2箇所ありますが、`messageList`の周りの`{ }`を取り除いて次のようにするとエラーが消えると思います。

[code]

                {messages.length === 0 ? <p>メッセージがありません</p> :
                    messageList
                }
    
[/code]

JSX内では`{ }`は任意の式を埋め込むための構文であり、この場合は`messages.length === 0 ? <p>メッセージがありません</p>
: messageList`が式です。これは`条件式 ? 真の場合 :
偽の場合`という構文を持つ条件演算子ですから、条件式が偽の場合に表示されるのは`messageList`であることになります。これは配列なので、こうすれば意図した挙動になります。

当初の`{ messageList }`では、これは「`messageList`を描画する」ではなく「`{ messageList
}`を描画する」という意味になります。ここでの`{ }`はJSX中で使う`{
}`とは異なる意味を持っています（この位置はJSX式ではないため）。これはオブジェクトリテラルであり、`{ messageList
}`は「`messageList`というプロパティを持つオブジェクト」という意味になります。そのため、Reactが「オブジェクトを描画しようとしている」としてエラーを発生させるのです。


CC BY-SA 4.0
2020-02-14T15:08:34.940
63055
2020-02-14T15:08:34.940
30079
63054
answer