Skip to content

Instantly share code, notes, and snippets.

@duncan60
Last active January 7, 2016 11:06
Show Gist options
  • Save duncan60/d7a21af5ea5cbf2538b1 to your computer and use it in GitHub Desktop.
Save duncan60/d7a21af5ea5cbf2538b1 to your computer and use it in GitHub Desktop.
redux practice
//https://egghead.io/lessons/javascript-redux-the-single-immutable-state-tree
//redux
const createStore = (reducer, initialState) => {
let state = initialState;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
};
};
return { getState, dispatch, subscribe }
};
/*const todoApp = (state = {}, action) => {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
}
};*/
//const { combineReducers } = Redux;
const combineReducers = (reducers) => {
return (state = {}, action) => {
return Object.keys(reducers).reduce(
(nextState, key) => {
nextState[key] = reducers[key](
state[key],
action
);
return nextState;
},
{}
);
};
}
//------reducer
const todo = (state, action) => {
switch (action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false
};
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state;
}
return {
...state,
completed: !state.completed
};
default:
return state;
}
};
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
case 'TOGGLE_TODO':
return state.map(t => todo(t, action));
default:
return state;
}
};
const visibilityFilter = (state = 'SHOW_ALL', action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
}
//---------action
let nextTodoId = 0;
const addTodo = (text)=> {
return {
type: 'ADD_TODO',
id: nextTodoId++,
text
};
};
const setVisibilityFilter = (filter) => {
return {
type: 'SET_VISIBILITY_FILTER',
filter
};
};
const toggleTodo = (id) => {
return {
type: 'TOGGLE_TODO',
id
};
};
const { Component } = React;
const { connect } = ReactRedux;
//---------AddTodo
let AddTodo = ({ dispatch }) => {
let input;
return (
<div>
<input ref={node => {
input = node;
}} />
<button
onClick={() => {
dispatch(addTodo(input.value));
input.value = '';
}}>
Add Todo
</button>
</div>
);
};
AddTodo = connect()(AddTodo);
//--------------VisibleTodoList
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed);
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed);
}
};
const Todo = ({onClick, completed, text}) => (
<li
onClick={onClick}
style={{
textDecoration:
completed ? 'line-through' : 'none'
}}>
{text}
</li>
);
const TodoList = ({todos, onTodoClick}) => (
<ul>
{todos.map(todo =>
<Todo
key ={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}/>
)}
</ul>
);
const mapStateToTodoListProps = (state) => {
return {
todos: getVisibleTodos(
state.todos,
state.visibilityFilter
)
};
}
const mapDispatchToTodoListProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id));
}
};
};
const VisibleTodoList = connect(
mapStateToTodoListProps,
mapDispatchToTodoListProps
)(TodoList);
//---------footer
const Link = ({active, children, onClick}) => {
if (active) {
return <span>{children}</span>;
}
return (
<a href='#'
onClick={(e) => {
e.preventDefault();
onClick();
}} >
{children}
</a>
);
};
const Footer = () => (
<p>
Show:
{''}
<FilterLink
filter='SHOW_ALL'>
All
</FilterLink>
{','}
<FilterLink
filter='SHOW_ACTIVE'>
Active
</FilterLink>
{','}
<FilterLink
filter='SHOW_COMPLETED'>
completed
</FilterLink>
</p>
);
const mapStateToLinkProps = (state, ownProps) => {
return {
active: ownProps.filter === state.visibilityFilter
};
};
const mapDispatchToLinkProps = (dispatch, ownProps) => {
return {
onClick: () => {
dispatch(setVisibilityFilter(ownProps.filter));
}
};
}
const FilterLink = connect(
mapStateToLinkProps,
mapDispatchToLinkProps
)(Link);
//------Provider
class Provider extends Component {
getChildContext() {
return {
store: this.props.store
};
}
render() {
return (
<TodoApp/>
);
}
}
Provider.childContextTypes = {
store: React.PropTypes.object
};
//---------Todo APP
const initialState = {
todos : [],
visibilityFilter: 'SHOW_ALL'
}
const rootReducers = combineReducers({
todos,
visibilityFilter
});
const appStore = createStore(rootReducers, initialState);
const TodoApp = () => (
<div>
<AddTodo />
<VisibleTodoList />
<Footer />
</div>
);
ReactDOM.render(
<Provider store={appStore} />,
document.getElementById('root')
);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="//cdnjs.cloudflare.com/ajax/libs/redux/3.0.5/redux.min.js"></script>
<script src="//fb.me/react-0.14.3.min.js"></script>
<script src="//fb.me/react-dom-0.14.3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/react-redux/4.0.1/react-redux.min.js"></script>
<title>JS Bin</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment