skip to Main Content

in general, I have a problem. I want to send a message to an endpoint, in which to send all messages from the database to the web socket topic so that the client can receive them all. Here is my method for sending a message (I use MONGODB):

@PostMapping("/send")
    public void sendMessage(@RequestBody Message message){
        mongoTemplate.insert(message);

    simpMessagingTemplate.convertAndSend("/topic/greetings", mongoTemplate.query(Message.class).as(Message.class).all());
    }

In general, nothing out of the ordinary, There are no problems with this, everything goes to the topic, everything is cool. Now all this needs to be caught on the client, for this I wrote the following code:

var stompClient: any = null;
const SockJS = require('sockjs-client')
const Stomp = require('stompjs')
function App() {
  const [posts, setPosts]: any = useState("")
  const [handleInput, setHandleInput] = useState("")


  function setValueInput(e: any){
    setHandleInput(e.target.value);
  }
  function sendMessage(e: any){
    e.preventDefault();
    axios.post('http://localhost:8080/api/send', {
      id: Date.now(),
      text: handleInput,
    })
        .then(function (response) {
          setHandleInput("");
        })
        .catch(function (error) {
          console.log(error);
        });
  }
  useEffect(function (){
      let Sock = new SockJS('http://localhost:8080/ws')

      stompClient= Stomp.over(Sock)

      stompClient.debug = null

      setTimeout(function() {
          stompClient.connect({},function (frame: any){


              console.log(`Connected: ${frame}`)


              stompClient.subscribe("/topic/greetings", function (greeting: any) {
                  console.log(greeting.body)
                  const tempParsedJson = JSON.stringify(greeting.body)
                  console.log(tempParsedJson)
                  setPosts(tempParsedJson)
              });

          }, 1200)})
  }, [])

  return (
    <div className="App">
        {posts && posts.map((data: any) => (
    <Form key={data.id} {...data}/>
            ))}
      <div className={style.dop}>
        <input onChange={setValueInput} value={handleInput} className={style.input}/>
        <a onClick={sendMessage} className={style.button}>Submit</a>
      </div>
    </div>
  );
}

export default App;

In short, we successfully subscribe to the topic, everything is fine again, but until I need to get the objects. In the console I see this:

enter image description here

The first is what I get from Java, the second is what I’m trying to translate into JSON. After sending messages, according to my code, we see that I am trying to display this data separately in each element, but when I try I get an error:

ERROR
posts.map is not a function

I hope you can help, I don’t know what to do. By the way, I tried to translate List in Java through gson to json, but the same error is displayed ..
Help please..
My Form:

const Form: React.FC<Props> = ({id, text}) => {
    function handleDelete(e: any) {
        e.preventDefault();
        axios.post('http://localhost:8080/api/deleteMessage', {
            id: id,
            text: text,
        })
            .then(function (response) {
            })
            .catch(function (error) {
                console.log(error);
            });
    }
    return (
        <div>
            <div className={style.wrapper}>
                <div className={style.coontainer}>
                    <div className={style.form}>
                        <p>{text}</p>
                        <a onClick={handleDelete} style={{display: "inline", margin: "0 20px", color: "white", cursor: "pointer"}}>Удалить</a>
                    </div>
                </div>
            </div>
        </div>
    );
};

export default Form;

3

Answers


  1. Because your code is async and not immediately fetched and might take time, until the data is fetched your data is undefined, and the posts are empty string until the data is fetched, then it’ll update to be replaced with data

    therefore this error was thrown to your console, because the String instance has no method named "map"

    so to solve this problem you have to solutions.

    the first one is to add the ternary operator (?) after the word posts, to be like that posts?.map() this will make the code only work if the data exists and it has a map method (in other words, if the data is an array)

    or the second solution is defining the initial state value an empty array

    Login or Signup to reply.
  2. First make initial state an empty array like this piece of code:

    const [posts, setPosts]: any = useState([]);
    

    And then, use ternary operator while using map function, like:

    posts && posts?.map(() => {})
    
    Login or Signup to reply.
  3. The other answers have picked up on the fact that you need posts to be initialised to be an array when you declare it using the useState hook in the following line:

      const [posts, setPosts]: any = useState([])       // [], not ""
    

    but they seem to have missed the problem in this piece of code:

                      console.log(greeting.body)
                      const tempParsedJson = JSON.stringify(greeting.body)
                      console.log(tempParsedJson)
                      setPosts(tempParsedJson)
    

    greeting.body looked good to me: according to your first console.log output, it looked to be an array containing some objects, and you could certainly .map over that if that were the case. However, on further inspection, if it actually were parsed JSON data, your browser would display that differently. In particular, you’d be able to expand parts of the JSON data.

    However, in the line below that, you’re not helping yourself.

    You take the data you have in greeting.body, and then you stringify it. You then name your variable to give yourself the impression you’ve ‘parsed’ JSON, which is unhelpful. You haven’t parsed JSON here, in fact, you’ve done the opposite. Parsing is the process of converting a string of JSON into JavaScript objects and arrays, stringifying is converting the other way.

    Therefore, the fix is not to call JSON.stringify on greeting.body, but to call JSON.parse on it instead.

    Your Java back-end may have send JSON over the network to your front-end. I would expect that Axios would have parsed this JSON into JavaScript objects for you, so you can start using them straight away, but for reasons I’m unsure about, this seems not to be the case.

    Note that I don’t have your back-end and haven’t run this code, so there could be other problems. I am only explaining how to fix the "posts.map is not a function" error.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search