Search code examples
javascriptreactjsreact-bootstrap

Displaying different tags or items based on conditionals in a map function


Background:

I have a react application where a user is able to type in a sentence. As the user types, the application will highlight the "negative" words in red. This is all working well. What I would like to do next, is display a tooltip over these words using Bootstrap's tooltip with a recommended alternative word. For simplicity in this question, all I really want to have is the phrase "Try something else?".

To display the words, I simply map the list of words and display them as headers with a conditional to add a class to the className if they are part of the list of negative words.

Problem:

Where I get stuck is how to display other items (that are not ) such as <OverlayTrigger> when that word is part of the negative list. Essentially my question is how can I efficiently display different items (< h5 >, < OverlayTrigger >, etc...) using conditionals?

Ideally I would like to display a header with specific properties if some condition is met, or display an OverlayTrigger with other specific properties if another condition is met.

Code:

import React, {Component} from 'react';
import "react-loader-spinner/dist/loader/css/react-spinner-loader.css";
import "./HomeComponent.css"
import $ from 'jquery';
const Sentiment = require('sentiment')
const sentiment = new Sentiment();

class HomeComponent extends Component {
    constructor(props) {
        super(props)
        this.state = {
            sentence: "",
            sentenceList: [],
            sentiment: {
                score: 0,
                negative: []
            }
        }
    }

    async componentDidMount() {
        $('[data-toggle="tooltip"]').tooltip();
    }

    async componentDidUpdate() {
        $('[data-toggle="tooltip"]').tooltip();
    }

    onChange = async (event) => {
        try {
            await this.setState({
                [event.target.name]: event.target.value,
                sentenceList: event.target.value.split(" "),
                sentiment: sentiment.analyze(event.target.value)
            })
        } catch (e) {
            console.log("Error occurred in OnChange")
        }
    }

    render() {
        return (
            <div className={"container"}>
                <h1>Natural Language Processing of a Sentence:</h1>
                <h5> User Input:</h5>
                <div className={"row"}>
                    <input
                        value={this.state.sentence}
                        type={"text"}
                        id={"sentence"}
                        name={"sentence"}
                        size={"125"}
                        onChange={this.onChange}
                    />
                </div>
                <hr className="rounded"/>
                <h5> Message to Remove Negatives</h5>
                <div className={"row"}>
                    {
                        this.state.sentenceList.map((word) => (
                            <h5 className={this.state.sentiment.negative.includes(word) ? "mr-1 negativeWord rounded" : "mr-1"}>
                                {word}
                            </h5>
                        ))
                    }
                </div>
            </div>
        )
    }
}

export default HomeComponent;

What I tried:

  1. I tried to add different conditionals like this:

         <div className={"row"}>
             {
                 this.state.sentenceList.map((word) => (
                     {
                         this.state.sentiment.negative.includes(word) &&
                             <h5>{word}</h5>
                     }
                     {
                         this.state.sentiment.negative.includes(word) &&
                         <OverlayTrigger>{word}</OverlayTrigger>
                     }
    
                 ))
             }
         </div>
    

This resulted in a failed to compile > Syntax error. I tried a few different ways of writing this, but they all resulted in something similar.

  1. I tried creating a new component in which I would pass {word}, and other items from the state as props, and handle the logic there. I ran into too many issues with updating render to the point that I gave up and went back to the conditionals above.

Any help would be appreciated!! Thanks!


Solution

  • You were close. This works:

    <div className={'row'}>
      {this.state.sentenceList.map((word) => (
        <>
          {this.state.sentiment.negative.includes(word) && <h5>{word}</h5>}
          {!this.state.sentiment.negative.includes(word) && <OverlayTrigger>{word}</OverlayTrigger>}
        </>
      ))}
    </div>
    

    Or better, the ternary syntax:

    <div className={'row'}>
      {this.state.sentenceList.map((word) => this.state.sentiment.negative.includes(word) ? <h5>{word}</h5> : <div>{word}</div>)}
    </div>