Redux
- A predictable container for Javascript applications, often used wth React. Redux provides a central location to store the state
of an application and allows components to access and modify the state.
- The data is stored in memory and volatile, when the application is closed so will the data.
- Structure
- You can import Redux with a library and it would have similar functionality as the example below.
- Entire state is stored in a single immutable object called the Store
- You can update/modify the state with the use of Dispatchers
- You can get data from the store with useSelector
function addTodoAction (todo) {
return ({
type: "ADD_TODO",
todo,
})
}
function removeTodoAction(id) {
return ({
type: "REMOVE_TODO",
id,
})
}
function toggleTodo(id) {
return ({
type: "TOGGLE_TODO",
id,
})
}
function addGoalAction (goal) {
return ({
type: "ADD_GOAL",
goal,
})
}
function removeGoalAction (id) {
return ({
type: "REMOVE_GOAL",
id,
})
}
const checker = (store) => (next) => (action) => {
if(action.type === 'ADD_TODO'
&& action.todo.name.toLowerCase().indexOf('bitcoin') !== -1){
return alert('Bad Idea')}
if(action.type === 'ADD_GOAL'
&& action.goal.name.toLowerCase().indexOf('bitcoin') !== -1){
return alert('Bad Idea')}
return next(action)
}
const logger = (store) => (next) => (action) => {
console.group(action.type)
console.log("The action: ",action)
const result = next(action)
console.log("The new state is: ", store.getState())
console.groupEnd()
return result;
}
function todos(state = [],action) {
if (action.type === 'ADD_TODO') {
return state.concat([action.todo])
} else if (action.type === 'REMOVE_TODO') {
return state.filter((todo) => todo.id !== action.id)
} else if (action.type === 'TOGGLE_TODO') {
return state.map((todo) => todo.id !== action.id ? todo :
Object.assign({},todo,{complete: !todo.complete})
)
}
else {
return state
}
}
function goals(state = [],action) {
switch(action.type) {
case 'ADD_GOAL':
return state.concat([action.goal])
case 'REMOVE_GOAL':
return state.filter((goals) => goals.id !== action.id)
default:
return state
}
}
function app(state = {},action) {
return {
todos:todo(state.todos,action),
goals:goals(state.goals,action)
}
}
function createStore (reducer){
let state
let listeners = []
const getState = () => state
const subscribe = (listener) => {
listeners.push(listener)
return () => {
listeners = listeners.filter((l) => l !== listener)
}
}
const dispatch = (action) => {
state = reducer(state,action)
listeners.forEach((listener) => listener())
}
return {
getState,
subscribe,
dispatch,
}
}
const store = Redux.createStore(Redux.combineReducers({
todos,
goals,
}), Redux.applyMiddleware(checker,logger))
function generateRandomId() {
return Math.random().toString(36).substring(2) + (new Date().getTime().toString(36));
}
function createRemoveButton (onClick) {
const removeBtn = document.createElement('button')
removeBtn.innerHTML = 'X'
removeBtn.addEventListener('click',onClick)
return removeBtn
}
function addTodo() {
const input = document.getElementById('todo')
const name = input.value
input.value = ''
store.dispatch(addTodoAction({
id:generateRandomId(),
name,
complete: false,
}))
}
function addGoal() {
const input = document.getElementById('goal')
const name = input.value
input.value = ''
store.dispatch(addGoalAction({
id:generateRandomId(),
name,
}))
}
store.subscribe(() => {
const {goals,todos} = store.getState()
document.getElementById('goals').innerHTML = ''
document.getElementById('todos').innerHTML = ''
goals.forEach(addGoalToDom)
todos.forEach(addToDoToDom)
})
document.getElementById('btnAddTodo').addEventListener('click',addTodo)
document.getElementById('btnAddGoal').addEventListener('click',addGoal)
function addToDoToDom(todo) {
const node = document.createElement('li')
const text = document.createTextNode(todo.name)
const removeBtn = createRemoveButton(() => {
store.dispatch(removeTodoAction(todo.id))
})
node.appendChild(text)
node.appendChild(removeBtn)
node.style.textDecoration = todo.complete ? 'line-through' : 'none'
node.addEventListener('click',() => {
store.dispatch(toggleTodo(todo.id))
})
document.getElementById('todos').appendChild(node)
}
function addGoalToDom(goal) {
const node = document.createElement('li')
const text = document.createTextNode(goal.name)
const removeBtn = createRemoveButton(() => {
store.dispatch(removeGoalAction(goal.id))
})
node.appendChild(text)
node.appendChild(removeBtn)
document.getElementById('goals').appendChild(node)
}