/* Example of a TODO app built using the Preact library */ import * as React from "preact/compat" // Core // Global application state let state /* Application logic is structured as pure functions with the signature `(state, ...args) => state`. This helper function wraps such a function so that its result updates the global state and can be used as an event handler. */ const handler = fn => (...args) => { state = fn(state, ...args) render() } // Higher-order function that injects the current state into a component const connect = comp => props => comp(props, state) const render = () => React.render(, document.body) // Initialize application state if not already restored from storage if (state == null) { state = { todos: [], text: "", filter: "ALL", } } window.addEventListener("load", render) // Components const App = () => (
) const Footer = () => (
Show: All Active Completed
) const FilterLink = connect(({ filter, children }, state) => { const disabled = state.filter == filter return ( ) }) const TodoList = connect((_, state) => ( )) const Todo = ({ todo }) => (
  • {todo.text}
  • ) const AddTodo = connect((_, state) => { return (
    ) }) // Selectors // Returns a filtered list of TODOs based on the current filter state function visibleTodos(state) { if (state.filter == "ALL") { return state.todos } else if (state.filter == "ACTIVE") { return state.todos.filter(t => !t.completed) } else if (state.filter == "COMPLETED") { return state.todos.filter(t => t.completed) } else { throw new Error("Unknown filter") } } // Reducers // Updates the input text state function changeText(state, e) { return { ...state, text: e.target.value } } // Updates the active filter state function changeFilter(filter, state) { return { ...state, filter } } // Creates a new TODO item if the input text is not empty function createTodo(state, e) { e.preventDefault() if (!state.text.trim()) { return state } return { ...state, todos: [...state.todos, { text: state.text }], text: "", } } // Toggles the completion state of a TODO item function toggleTodo(todo, state) { return { ...state, todos: state.todos.map(t => t == todo ? { ...todo, completed: !todo.completed } : t, ), } }