0

In my jsx file I have the following function:

function GetComments({commentsArray}) {
        return commentsArray.map((comment) => {
        let localId = comment.LocalId;
          return (
            <div className="comments-container">
                <div className="commenter">
                    <span className="id-label">{comment.LocalId}</span>
                        <script>
                            if (comment.ParentCommentId !== null) {
                               document.write("<span class=reply title=in reply to " + comment.LocalId + "></span>") 
                            }
                        </script>
                </div>
            </div>
          );
        });
}

Now I don't get any errors but when that script tag part is in there, the page just doesn't load, it's just constantly stuck trying to load. Where have I gone wrong with adding a script to this? I am only wanting that element created when that condition is met. I have been looking online and I see that it's different in jsx for adding scripts but confused on how to correctly implement my script

1
  • Is it necessary for it to be contained within a <script> tag? Conditional rendering would work, as dheeraj pointed out, but I think the script and document.write() can be removed. Commented Aug 13, 2022 at 17:59

2 Answers 2

1

There are a few problems with your code, the biggest of which is the use of document.write, which you should never be using in react code. To understand why, it's important to realize that one of the most fundamental design goals of react is to abstract any direct manipulation of the DOM away from the programmer and instead allow them to specify the way in which a lighter weight virtual DOM reacts to state changes. Try something like the following:

export function GetComments({ commentsArray }) {
  return (
    <>
      {commentsArray.map((comment) => {
        const localId = comment.LocalId;
        return (
          <div key={localId} className="comments-container">
            <div className="commenter">
              <span className="id-label">{localId}</span>
              {comment.ParentCommentId && (
                <span className="reply" title={`in reply to ${localId}`} />
              )}
            </div>
          </div>
        );
      })}
    </>
  );
}

In addition to doing away with document.write, this addresses the following issues:

  1. Consistent use of localId.
  2. Conditional rendering to render the "reply" span when comment.ParentCommentId is truthy.
  3. Template literals to more clearly express the "in reply to" string. This is maybe a bit more of a style issue than a functional one, but template literals are the modern way to format variables into string templates.
  4. The use of key inside the map to "help React identify which items have changed, are added, or are removed."
  5. Wrapping the whole map expression in a fragment so that it has a return type which is not an array, which is a requirement for it being used as a JSX element.
Sign up to request clarification or add additional context in comments.

5 Comments

Thank for the really detailed answer, much appreciated. However would you know why for the <> just after the first return I am getting an "unexpected token" error?
You could be using an older version of react. The so-called short syntax for fragments was introduced in v16.2.0. If you are for some reason tied to an earlier version, you can use <React.Fragment> ... </React.Fragment> instead.
ah that was it thanks. Still having an issue though as it is printing out comment.ParentCommentId && for each element rather than that being a condition if that makes sense?
That was my fault forgetting to surround that section in curly braces. Please see the revised code.
That was it, working now. Thank you for that and thanks again for the in depth explanation, given me a much better understanding on how it works and how I should be going about this
0

I have managed to actually come up with a way to solve the issue, don't know if this is the best way.

I created an additional function where I pass the id into it and do the check there.

function ParentIdCheck({id}) {
    if (id !== null) {
        return(
            <span className="reply" title={"in reply to " + id}></span>
        );
    }
}

and now the original function looks like:

function GetComments({commentsArray}) {
        return commentsArray.map((comment) => {
        let localId = comment.LocalId;
          return (
            <div className="comments-container">
                <div className="commenter">
                    <span className="id-label">{comment.LocalId}</span>
                    <ParentIdCheck id = {comment.ParentCommentId}/>
                </div>
            </div>
          );
        });
}

I don't know if this is the best way though, so open to suggestions on how to improve this

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.