Ishan Jain Ishan Jain - 3 months ago 10
Javascript Question

Why does clicking on a tab that changes state and has nothing to do with ajax call creates that ajax call?

I have a simple layout.

There is a

<StateSelector>
in
<Navbar>
clicking on that executes a method.

The value of innerHTML of that button in
<StateSelector>
is passed as an argument to a function that was passed to it as a prop. And the method present in parent changes the
activeOption
State to
All, Offline and online
depending on the button clicked.

Now, There is one more child to this parent called
<TwitchList>
. This
<TwitchList>
's render method contains an array of 8 users names and 8 calls are made to
twitch.tv
to get data for those channels.

Note that I have not linked
<StateSelector>
just yet. It has no interaction to
$.ajax();
in
<TwitchList>
except the fact that
<TwitchList>
and
<StateSelector>
belong to same parent.

Why does clicking on a element inside
<StateSelector>
generating ajax calls?
And clicking on it one time generates 8 calls which is equal to number of users in usersList[].

I have tried searching for this issue and I have tried to work my way around for about 4 days now and I just don't understand why it is happenning.

var Navbar = React.createClass({
render: function () {
return (
<div className="navbar">
<h1 className="header">TWITCH STREAMERS</h1>
<StateSelector changeActiveOption={this.props.changeActiveOption}/>
</div>
);
}
});

var StateSelector = React.createClass({
changeOption: function (e) {
this.props.changeActiveOption(e.target.innerHTML.toLowerCase());
},
render: function () {
return (
<div className="selectorList">
<div className="selector" onClick={this.changeOption}>ALL</div>
<div className="selector" onClick={this.changeOption}>ONLINE</div>
<div className="selector" onClick={this.changeOption}>OFFLINE</div>
</div>
);
}
});
var TwitchList = React.createClass({
render: function () {
var userslist = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
var finalList = [];
function makeURL(user, type) {
return "https://api.twitch.tv/kraken/" + type + "/" + user;
}
userslist.forEach(function (user) {
$.ajax({
url: makeURL(user, "streams"),
dataType: 'jsonp',
success: function (data) {
function getID(data) {
if (data.stream) {
return data.stream._id;
} else {
return Math.random();
}
}
function getImage(data) {
if (!data.stream) {
return "https://dummyimage.com/50x50/ecf0e7/5c5457.jpg&text=0x3F";
}
else {
return data.stream.preview.medium;
}
}
console.log(data);
var id = getID(data);
var preview = getImage(data);
console.log(preview);
finalList.push(
<li className="twitchUser" key={id}>
<img src={preview} alt="preview"/>
</li>
)
},
fail: function (xhr, error, url) {
console.error(error + " " + xhr + " " + url);
}
});
});
return (
<div className= "twitchListWraper" >
<ul className="twitchList">
{finalList}
</ul>
</div>
)
}
});
var App = React.createClass({
getInitialState: function () {
return {
activeOption: "all"
};
},
changeActiveOption: function (option) {
this.setState({
activeOption: option
});
},
render: function () {
return (
<div className="app-root">
<Navbar changeActiveOption={this.changeActiveOption}/>
<TwitchList activeOption={this.state.activeOption}/>
</div>
);
}
});

ReactDOM.render(<App />, document.getElementById('root'));


JSBin: http://jsbin.com/sulihogegi/edit?html,css,js,console,output

Answer

Every time state changes on <App>, it re-renders. This includes re-rendering its children (on of which is <TwitchList>). Your ajax call is made in <TwitchList>'s render function, so every time state changes, it's going to be hitting that ajax code.

If you're wondering why the state's changing, it's because you have a function, changeActiveOption, that updates the <App>'s state being passed to <Navbar> which is then passes down to <StateSelector>.

The appropriate thing to do here is find a life cycle event in which to make the ajax call. I'd recommend componentWillMount and componentWillUpdate.

Take a look at lifecycle functions here.

Comments