\$\begingroup\$
\$\endgroup\$
I have made a small app in React that fulfils the following user stories:
GIVEN I add an item using the form
THEN I see the text appear in the list below
GIVEN I see items in the list
AND I click the close button next to a list item
THEN the list item disappears from the page
GIVEN I refresh the page at any point
THEN I see the list that I saw on the page before I refreshed
Here is my code:
const TodoInput = props => {
return (
<form>
<div>Enter a todo</div>
<input
type="text"
onChange={props.onHandleChangeInputVal}
value={props.inputVal}
/>
<button
type="submit"
onClick={props.onHandleAddTodo}
>
Add to the list
</button>
</form>
)
};
class TodosList extends React.Component {
constructor() {
super();
this.state = {
inputVal: '',
todos: []
};
this.onHandleChangeInputVal = this.onHandleChangeInputVal.bind(this);
this.onHandleAddTodo = this.onHandleAddTodo.bind(this);
}
componentDidMount() {
const todosFromLocalStorage = JSON.parse(localStorage.getItem('localStorageTodos'));
this.setState({
todos: todosFromLocalStorage || []
})
}
getTodos() {
const todos = this.state.todos;
return todos.map((todo, index) => {
return (
<li
key={index}
>
{todo}
<button onClick={event => this.onHandleDeleteTodo(event, index)}>×</button>
</li>
)
})
}
onHandleChangeInputVal(e) {
const newInputVal = e.target.value;
this.setState({
inputVal: newInputVal
})
}
onHandleAddTodo(e) {
e.preventDefault();
let todosCopy = this.state.todos.slice();
if (this.state.inputVal) {
todosCopy.push(this.state.inputVal);
}
this.setState({
todos: todosCopy,
inputVal: ''
}, () => {
this.updateLocalStorageWithState();
});
}
onHandleDeleteTodo(event, indexOfItemToRemove) {
event.preventDefault();
let todosCopy = this.state.todos.slice();
todosCopy.splice(indexOfItemToRemove, 1);
this.setState({
todos: todosCopy
}, () => {
this.updateLocalStorageWithState();
});
}
updateLocalStorageWithState() {
localStorage.setItem('localStorageTodos', JSON.stringify(this.state.todos));
}
render() {
const todos = this.getTodos();
return (
<div>
<TodoInput
onHandleChangeInputVal={this.onHandleChangeInputVal}
onHandleAddTodo={this.onHandleAddTodo}
inputVal={this.state.inputVal}
/>
<ul>{todos}</ul>
</div>
)
}
}
ReactDOM.render(<TodosList />, document.getElementById('app'));
Here is a demo: http://codepen.io/alanbuchanan/pen/RoKBLr?editors=0010
Please can you review for any improvements to how I have structured and written my code?
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Nov 20, 2016 at 1:36
1 Answer 1
\$\begingroup\$
\$\endgroup\$
Overall, I like your code. Especially, since you have the TodoInput
as a separate stateless component. IMHO, there is still some room for improvement, though:
- You shouldn't use
setState
incomponentDidMount
since this will trigger a re-rendering. SincelocalStorage.getItem
is synchronous anyway, you can initialise the state in the constructor and removecomponentDidMount
completely. - If you change the signature of
onHandleDeleteTodo
, you don't need to referenceevent
ingetTodos
:
getTodos() {
// ...
<button onClick={this.onHandleDeleteTodo(index)}
// ...
}
onHandleDeleteTodo(indexOfItemToRemove) {
return (event) => {
event.preventDefault();
let todosCopy = this.state.todos.slice();
todosCopy.splice(indexOfItemToRemove, 1);
this.setState({
todos: todosCopy
}, () => {
this.updateLocalStorageWithState();
});
}
}
- I would probably use
Array.concat
instead ofArray.slice
andArray.push
(inonHandleAddTodo
) - You don't need the extra arrow function in
onHandleAddTodo
:
this.setState({
todos: todosCopy
}, () => {
this.updateLocalStorageWithState();
});
is equivalent to
this.setState({
todos: todosCopy
}, this.updateLocalStorageWithState);
- The prefix
onHandle
doesn't sound right to me. I would probably just useon
for the naming of the prop (i.e.props.onChangeInputVal
inTodoInput
) andhandle
for the actual implementation that will be passed down (i.e.handleChangeInputVal
inTodosList
. Furthermore, I would rename the propinputVal
tovalue
since that is the naming convention used for form elements in React.
default