Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize things a little bit #1

Merged
merged 7 commits into from
Apr 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"presets": ["es2015", "react"],
"plugins": ["transform-object-rest-spread"],
"env": {
"development": {
"presets": ["react-hmre"]
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
dist/
dist/*.js
npm-debug.log
node_modules/
7 changes: 6 additions & 1 deletion actions/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as types from '../constants/ActionTypes'

let nextId = 0;
export function addTodo(text) {
return { type: types.ADD_TODO, text }
return { type: types.ADD_TODO, text, id: (nextId++).toString() }
}

export function deleteTodo(id) {
Expand All @@ -23,3 +24,7 @@ export function completeAll() {
export function clearCompleted() {
return { type: types.CLEAR_COMPLETED }
}

export function setFilter(filter) {
return { type: types.SET_FILTER, filter }
}
13 changes: 13 additions & 0 deletions components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { PropTypes } from 'react'
import Header from '../components/Header'
import MainSection from '../components/MainSection'
import * as TodoActions from '../actions'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This TodoActions import is useless here, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, missed this one. Doesn't affect the perf though.


const App = () => (
<div>
<Header />
<MainSection />
</div>
)

export default App
32 changes: 32 additions & 0 deletions components/FilterLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import { connect } from 'react-redux'
import classnames from 'classnames'
import { setFilter } from '../actions'
import { SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED } from '../constants/TodoFilters'

const FILTER_TITLES = {
[SHOW_ALL]: 'All',
[SHOW_ACTIVE]: 'Active',
[SHOW_COMPLETED]: 'Completed'
}

const FilterLink = ({ filter, selected, onClick }) => (
<a className={classnames({ selected })}
style={{ cursor: 'pointer' }}
onClick={onClick}>
{FILTER_TITLES[filter]}
</a>
)

const mapStateToProps = (state, ownProps) => ({
selected: state.filter === ownProps.filter
})

const mapDispatchToProps = (dispatch, ownProps) => ({
onClick: () => dispatch(setFilter(ownProps.filter))
})

export default connect(
mapStateToProps,
mapDispatchToProps
)(FilterLink)
121 changes: 54 additions & 67 deletions components/Footer.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,60 @@
import React, { PropTypes, Component } from 'react'
import classnames from 'classnames'
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import FilterLink from './FilterLink'
import { getCompletedCount, getListedCount } from '../reducers'
import { clearCompleted } from '../actions'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'

const FILTER_TITLES = {
[SHOW_ALL]: 'All',
[SHOW_ACTIVE]: 'Active',
[SHOW_COMPLETED]: 'Completed'
}

class Footer extends Component {
renderTodoCount() {
const { activeCount } = this.props
const itemWord = activeCount === 1 ? 'item' : 'items'

return (
<span className="todo-count">
<strong>{activeCount || 'No'}</strong> {itemWord} left
</span>
)
}

renderFilterLink(filter) {
const title = FILTER_TITLES[filter]
const { filter: selectedFilter, onShow } = this.props

return (
<a className={classnames({ selected: filter === selectedFilter })}
style={{ cursor: 'pointer' }}
onClick={() => onShow(filter)}>
{title}
</a>
)
}

renderClearButton() {
const { completedCount, onClearCompleted } = this.props
if (completedCount > 0) {
return (
<button className="clear-completed"
onClick={onClearCompleted} >
Clear completed
</button>
)
}
}

render() {
return (
<footer className="footer">
{this.renderTodoCount()}
<ul className="filters">
{[ SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED ].map(filter =>
<li key={filter}>
{this.renderFilterLink(filter)}
</li>
)}
</ul>
{this.renderClearButton()}
</footer>
)
}
}

const TodoCount = ({ activeCount }) => (
<span className="todo-count">
<strong>{activeCount || 'No'}</strong>
{' '}
{activeCount === 1 ? 'item' : 'items'} left
</span>
)

const ClearButton = ({ completedCount, clearCompleted }) => (
<button className="clear-completed"
onClick={clearCompleted} >
Clear completed
</button>
)

const Footer = ({ filter, completedCount, listedCount, clearCompleted }) => (
listedCount ? (
<footer className="footer">
<TodoCount activeCount={listedCount - completedCount} />
<ul className="filters">
{[ SHOW_ALL, SHOW_ACTIVE, SHOW_COMPLETED ].map(filter =>
<li key={filter}>
<FilterLink filter={filter} />
</li>
)}
</ul>
{completedCount > 0 &&
<ClearButton
completedCount={completedCount}
clearCompleted={clearCompleted}
/>
}
</footer>
) : (
<span />
)
)
Footer.propTypes = {
completedCount: PropTypes.number.isRequired,
activeCount: PropTypes.number.isRequired,
filter: PropTypes.string.isRequired,
onClearCompleted: PropTypes.func.isRequired,
onShow: PropTypes.func.isRequired
listedCount: PropTypes.number.isRequired,
completedCount: PropTypes.number.isRequired,
}

export default Footer
const mapStateToProps = (state) => ({
filter: state.filter,
listedCount: getListedCount(state),
completedCount: getCompletedCount(state),
})

export default connect(
mapStateToProps,
{ clearCompleted }
)(Footer)
42 changes: 21 additions & 21 deletions components/Header.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import React, { PropTypes, Component } from 'react'
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import TodoTextInput from './TodoTextInput'
import { addTodo } from '../actions'

class Header extends Component {
handleSave(text) {
if (text.length !== 0) {
this.props.addTodo(text)
}
}

render() {
return (
<header className="header">
<h1>todos</h1>
<TodoTextInput newTodo
onSave={this.handleSave.bind(this)}
placeholder="What needs to be done?" />
</header>
)
}
}

const Header = ({ addTodo }) => (
<header className="header">
<h1>todos</h1>
<TodoTextInput
newTodo
placeholder="What needs to be done?"
onSave={text => {
if (text.length !== 0) {
addTodo(text)
}
}}
/>
</header>
)
Header.propTypes = {
addTodo: PropTypes.func.isRequired
}

export default Header
export default connect(
null,
{ addTodo }
)(Header)
105 changes: 24 additions & 81 deletions components/MainSection.js
Original file line number Diff line number Diff line change
@@ -1,83 +1,26 @@
import React, { Component, PropTypes } from 'react'
import React, { PropTypes } from 'react'
import { connect } from 'react-redux'
import TodoItem from './TodoItem'
import ToggleAll from './ToggleAll'
import Footer from './Footer'
import { SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE } from '../constants/TodoFilters'

const TODO_FILTERS = {
[SHOW_ALL]: () => true,
[SHOW_ACTIVE]: todo => !todo.completed,
[SHOW_COMPLETED]: todo => todo.completed
}

class MainSection extends Component {
constructor(props, context) {
super(props, context)
this.state = { filter: SHOW_ALL }
}

handleClearCompleted() {
this.props.actions.clearCompleted()
}

handleShow(filter) {
this.setState({ filter })
}

renderToggleAll(completedCount) {
const { todos, actions } = this.props
if (todos.length > 0) {
return (
<input className="toggle-all"
type="checkbox"
checked={completedCount === todos.length}
onChange={actions.completeAll} />
)
}
}

renderFooter(completedCount) {
const { todos } = this.props
const { filter } = this.state
const activeCount = todos.length - completedCount

if (todos.length) {
return (
<Footer completedCount={completedCount}
activeCount={activeCount}
filter={filter}
onClearCompleted={this.handleClearCompleted.bind(this)}
onShow={this.handleShow.bind(this)} />
)
}
}

render() {
const { todos, actions } = this.props
const { filter } = this.state

const filteredTodos = todos.filter(TODO_FILTERS[filter])
const completedCount = todos.reduce((count, todo) =>
todo.completed ? count + 1 : count,
0
)

return (
<section className="main">
{this.renderToggleAll(completedCount)}
<ul className="todo-list">
{filteredTodos.map(todo =>
<TodoItem key={todo.id} todo={todo} {...actions} />
)}
</ul>
{this.renderFooter(completedCount)}
</section>
)
}
}

MainSection.propTypes = {
todos: PropTypes.array.isRequired,
actions: PropTypes.object.isRequired
}

export default MainSection
import { getVisibleTodoIds } from '../reducers'

const MainSection = ({ visibleIds }) => (
<section className="main">
<ToggleAll />
<ul className="todo-list">
{visibleIds.map(id =>
<TodoItem key={id} id={id} />
)}
</ul>
<Footer />
</section>
)

const mapStateToProps = (state) => ({
visibleIds: getVisibleTodoIds(state)
})

export default connect(
mapStateToProps
)(MainSection)
Loading