Modify the state of our app
It's our time to work with change detection
mechanisms!
Mutating functions in component definition
We're going to add the methods
objects that we've created in Our own state management system.
Quick remember
It was the set of functions that should modify the actual state of the app. In the previous section they were just doing nothing.
We're going to give them a real aim 😃
In ./framework/index.js
, add the methods props to the template argument:
export const createComponent = ({
template,
methods = {},
initialState = {}
}) => props => template({ ...props, methods });
And guess what? We can now call our methods
directly in our ./src/user.js
component!
import { createComponent } from "../framework";
import { div } from "../framework/element";
import { onClick } from "../framework/event";
const methods = {
changeName: (state, firstName) => ({ ...state, firstName })
};
const initialState = { firstName: "Marvin", lastName: "Frachet" };
const template = ({ firstName, lastName, methods }) =>
div`${onClick(() =>
methods.changeName("Thomas")
)} Hello ${firstName} ${lastName}`;
export const User = createComponent({ template, methods, initialState });
Important note on methods
Take a look at the way we're calling methods.changeName('Thomas')
in the component.
Oh wait! We previously defined changeName = (state, firstName) => (/*...*/)
, is that a mistake?
Nop, it's actually the way I would like the framework to work. Every time I call a method on the methods
object, I will
implicitly pass the state
thanks to the black box.
Let's modify ./framework/index.js
to have a better understanding of the previous note:
import * as snabbdom from "snabbdom";
const patch = snabbdom.init([
require("snabbdom/modules/eventlisteners").default
]);
export const init = (selector, component) => {
const app = document.querySelector(selector);
patch(app, component.template);
};
let state = {};
export const createComponent = ({
template,
methods = {},
initialState = {}
}) => {
state = initialState;
const mappedMethods = Object.keys(methods).reduce(
(acc, key) => ({
...acc,
[key]: (...args) => {
state = methods[key](state, ...args);
console.log(state); // this prints "Thomas" as firstName :D
return state;
}
}),
{}
);
return props => template({ ...props, ...state, methods: mappedMethods });
};
Tricky part... sorry
This part is a bit tricky. I'm working in a way to simplify it. It creates headaches just to read it again and again...
And let's now change the user component:
import { createComponent } from "../framework";
import { div } from "../framework/element";
import { onClick } from "../framework/event";
const methods = {
changeName: (state, firstName) => ({ ...state, firstName })
};
const initialState = { firstName: "Marvin", lastName: "Frachet" };
const template = ({ firstName, lastName, methods }) =>
div`${onClick(() =>
methods.changeName("Thomas")
)} Hello ${firstName} ${lastName}`;
export const User = createComponent({ template, methods, initialState });