React
by nbrustein
HTML
<div id="app"></div>
CSS
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
li {
margin: 8px 0;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
.done {
color: rgba(0, 0, 0, 0.3);
text-decoration: line-through;
}
input {
margin-right: 5px;
}
React
const { useState, useReducer } = React;
/*
This first component does not work because, even
after running useReducer, myModel is still the same
model. Nothing has changed, so react does not re-render.
*/
function DontWork() {
const myModel = useModel()[0];
const updateProperty = useReducer((myModel, newValue) => {
myModel.property = newValue;
return myModel;
}, myModel)[1];
return (
<div>
<h1>Don't work</h1>
<input
onChange={
(e) => {
updateProperty(e.target.value);
}
}
/>
<span>{myModel.property}</span>
</div>
)
}
/*
It works if I'm willing to clone the model, but that seems like a waste, especially if the model is more complex.
But, I'm also not much of a functional programmer, so maybe I should just get over it and accept that cloning things is good in functional programming?
*/
function WorksIfICloneIt() {
const [myModel, updateModel] = useModel();
const updateProperty = function(newValue) {
const clone = new Model({property: newValue});
updateModel(clone);
}
return (
<div>
<h1>Works if I clone it</h1>
<input
onChange={
(e) => {
updateProperty(e.target.value);
}
}
/>
<span>{myModel.property}</span>
</div>
)
}
/*
I can make it work using the forceUpdate strategy
at https://medium.com/crowdbotics/how-to-use-usereducer-in-react-hooks-for-performance-optimization-ecafca9e7bf5
This makes it work, but there are two things I don't like about it:
1. React recommends against using forceUpdate, and I'm not comfortable enough with my React skills to know when it's okay to ignore that warning.
2. If I were to run into this problem again and again, I would always end up having to use useReducer and useForceUpdate and then calling both updateProperty and forcceUpdate in the onChange. Not totally dry.
*/
function WorksUgly() {
const myModel...