React

by dance2die

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;


function modelReducer(state, action) {
	switch (action.type) {
  	case 'UPDATE_PROPERTY': 
    	// return a new object reference
    	return Object.assign({}, action.model, {property: action.property});
  	default: return state;
  }
}

/*
	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];
   */  
  const [model, dispatch] = useReducer(modelReducer, myModel);

  return (
    <div>
      <h1>Now Works</h1>
      <input
        onChange={e => dispatch({type: 'UPDATE_PROPERTY', model, property: e.target.value})}
      /> 
      <span>{model.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...