2

I am needing to create a button as people search for locations. When a user clicks on the button it should run an onClick function. However because it is an innerHTML += button it seems to not want to find the function.

The error Can't find variable: addToResult

class NewCampaign extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          value: null
        };
      }
    
  
    


    render(){
        var currentTimeoutId;
        var areas = [];

       
        function addToResult(e){
            areas.push(e);
        }

        function checkAnswer(event, e) {
    
            if(currentTimeoutId){
                clearTimeout(currentTimeoutId);
             }
         
             currentTimeoutId = setTimeout(function(){
                 currentTimeoutId = null;
                    axios.get('https://nominatim.openstreetmap.org/search.php?city='+e+'&countrycodes=AU&featuretype=county&polygon_geojson=1&format=json')
                    .then(function (response) {
                    // handle success
                    document.getElementById("results").innerHTML = "";
                    for (let i = 0; i < response.data.length; i++) { 
                        document.getElementById("results").innerHTML +="<button onClick={addToResult("+response.data[i].osm_id+")}>ID:"+response.data[i].osm_id+" - "+response.data[i].display_name+"</button>\n\n"
                    }
        
                    })
                    .catch(function (error) {
                    // handle error
                    console.log(error);
                    })
                    .then(function () {
                    // always executed
                    });
                },1000);
        
        }
        return (
            <React.Fragment>
                <div>
            <input name="search" id="search" placeholder='Suburbs'
             value={this.state.value}
             onChange={e => {this.setState({ value: e.currentTarget.value})}}
             onKeyUp={(event) => {checkAnswer(event, this.state.value)}} />
            <div id="results"></div>
            <div id="debug"></div>
             
       
            </div></React.Fragment>  );
    }
}

export default NewCampaign;

After more research I worked out I need to do something like the following

    checkAnswer = (event, e) => {
        if(currentTimeoutId){
            clearTimeout(currentTimeoutId);
         }
     
         currentTimeoutId = setTimeout(function(){
             currentTimeoutId = null;
             alert(e)
                axios.get('https://nominatim.openstreetmap.org/search.php?city='+e+'&countrycodes=AU&featuretype=county&polygon_geojson=1&format=json')
                .then(response => {
                    console.log(response);
                    return response.data.map(user => ({
                      Id: `${user.osm_id}`,
                      name: `${user.place_id}`,
                      Company: `${user.display_name}`,
                    }))
                  })
                      .then(users => {
                        this.setState({
                          users,
                          isLoading: true
                        });
                      })
                  .catch(function (error) {
                // handle error
                console.log(error);
                })
                .then(function () {
                // always executed
                
                //alert(response)
                });
            },1000);
    
    }   

However I am still getting

TypeError: _this.setState is not a function. (In '_this.setState({
                        users: users,
                        isLoading: true
                    })', '_this.setState' is undefined)

HoweverI defined it in

   constructor(props) {
        super(props);
        this.state = {
          value: null,
          users: [],
          isLoading: false
        };
      }

Note I was able to get it to work if it was auto loader at launch

https://codepen.io/redimongo/pen/dydNbGX?editors=1111

was a simple fix

I changed

currentTimeoutId = setTimeout(function(){

to

currentTimeoutId = setTimeout(() => {
RussellHarrower
  • 6,470
  • 21
  • 102
  • 204
  • 1
    You're going to have to think in terms of React and change your approach. Mixing native DOM methods like `innerHTML` with the specific way React updates the DOM is never a good idea, and will cause you a lot of problems. – Andy May 15 '22 at 13:47
  • @Andy I figured that out, after I posted - I am searching for a dropbox plugin, but all require you to refill. Is there away a input can talk to a function and return in a DIV? – RussellHarrower May 15 '22 at 13:53

1 Answers1

0

The error is due to this piece of your code:

"<button onClick={addToResult("+response.data[i].osm_id+")}>ID:"+response.data[i].osm_id+" - "+response.data[i].display_name+"</button>\n\n"

I would suggest you make another component to render both "addToResult" as well as the inner content instead of using the ".innerHTML"

A possible good approach would be to have a state for the results of your data fetching:

const [results,setResults] = useState([]);

Then, you could have a custom Button to render each result:

const Button = ({onClick, children}) => <button onClick={onClick}>{children}</button>

and later on your render section just map the results and display them like:

{results.map(result => <Button onClick={}>{result.osm_id}</Button>}
helrabelo
  • 491
  • 4
  • 8