CountGradsky CountGradsky - 1 month ago 19
React JSX Question

ReactJS updating coomponents and passing array as argument?

I'm new to ReactJS and I fell I'm missing some fundamental information.

I am working on simple TODO list, where you click on <li> and it gets transfered to Finished section.
http://jsbin.com/gadavifayo/1/edit?html,js,output

I have 2 arrays that contain list of tasks, when you click on one task <li> it is removed from array and transferred to other array. After that clicked <ul> is updated but not the one where task went.

When using it you may notice that <ul> is updated only when clicked.
How can I update both <ul> when clicking on only one?

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testing</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<div id="react-app"></div>
<script src="https://fb.me/react-0.14.3.js"></script>
<script src="https://fb.me/react-dom-0.14.3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel">
/*
* Components
*/
var pendingItems = [
'Clean the room',
'Get milf',
'Sellout and stuff'
];

var finishedItems = [
'Clean the room',
];

var TodoList = React.createClass({
getInitialState: function() {
return { items: this.props.list };
},
handleClick: function(i) {
console.log('You clicked: ' + i + ':' + this.props.listString);
if (this.props.listString == "pendingItems") {
var removed = this.state.items.splice(i, 1);
finishedItems.push(removed);
};
if (this.props.listString == "finishedItems") {
var removed = this.state.items.splice(i, 1);
pendingItems.push(removed);
};

this.forceUpdate()
},

render: function() {
return (
<ul>
{this.state.items.map(function(item, i) {
return (
<li onClick={this.handleClick.bind(this, i)} key={i}>{this.state.items[i]}</li>
);
}, this)}
</ul>
);
},
});

var Layout = React.createClass({
render: function (){
return (
<div className='col-xs-12'>
<div className='col-xs-6'>
<TodoList list={pendingItems} listString="pendingItems"/>
</div>
<div className='col-xs-6'>
<TodoList list={finishedItems} listString="finishedItems"/>
</div>
<div className='col-xs-6'></div>
</div>

)
}
});

ReactDOM.render(<Layout />, document.getElementById('react-app'));
</script>

</body>
</html>

Answer

You need to use the states. In getInitialState you put your two list, onclick do whatever transformationyou want (you then have for example updated_list1 and updated_list2 and then you set the list like that:

this.setState({ list1: updated_list1, list2: updated_list2 }); in your case this.setState({ pendingItems: pendingItems ... after the .push

the setState function will automatically rerender, no need to call forceupdate.

The second thing important here is that you have to make the two list communication kinda, so my advise would be to put your both ul in the same component (so you can manage the lists in the same component state as mentionned above).

However this is not the only way to go and you may choose the put the states of your two list in the parent component (Layout). In this case you should use this way to go. https://facebook.github.io/react/tips/expose-component-functions.html

In any case you need (if you want to keep it simple and without external model management like backbone or flux pattern) to put lists states in the same component state. (reminder: method 1 => ul in the same componenet so the states too, method 2 => keep state in the parent component)

Comments