Skip to content

Instantly share code, notes, and snippets.

@mattboldt
Last active September 25, 2019 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattboldt/b1fbeb8d562a5edfbf2d922ac96fddc8 to your computer and use it in GitHub Desktop.
Save mattboldt/b1fbeb8d562a5edfbf2d922ac96fddc8 to your computer and use it in GitHub Desktop.
React Classes v.s. Hooks when communicating with a REST api
const List = () => {
// Items would come from an API
const items = [{ id: 1, active: true, complete: false }, ...]
return (
<ul>
{items.map((item) => (
<ListItem item={item} />
))}
</ul>
)
}
// CLASS BASED VERSION
class ListItem extends Component {
state = {
active: props.item.active,
complete: props.item.complete,
}
// Request is sent as a callback after state updates
updateItem = () => {
fetch(`http://my-api/items/${this.props.item.id}`, {
method: 'PUT',
body: { item: this.state },
})
}
render() {
return (
<li>
Active:
<input
type="checkbox"
checked={this.state.active}
onChange={(e) => this.setState({ active: e.target.checked }, this.updateItem)}
/>
Complete:
<input
type="checkbox"
checked={this.state.complete}
onChange={(e) => this.setState({ complete: e.target.checked }, this.updateItem)}
/>
</li>
)
}
}
// HOOKS VERSION
const ListItem = ({ item }) => {
const [active, setActive] = useState(item.active)
const [complete, setComplete] = useState(item.complete)
// useEffect fires on mount AND update, which is not desired.
// Can be fixed by using a custom hook, but the React docs say this is rare? Is this an anti-pattern?
// https://reactjs.org/docs/hooks-faq.html#can-i-run-an-effect-only-on-updates
//
// Furthermore, upon testing this with a custom useDidUpdate hook, my state was not always in sync
// and the PUT requests were sending stale data. Idk if this flow is appropriate for my use case?
useEffect(() => {
fetch(`http://my-api/items/${item.id}`, {
method: 'PUT',
body: { item: { active, complete } },
})
}, [active, complete])
return (
<li>
Active:
<input type="checkbox" checked={active} onChange={(e) => setActive(e.target.checked)} />
Complete:
<input type="checkbox" checked={complete} onChange={(e) => setComplete(e.target.checked)} />
</li>
)
}
// Potential fix:
const reducer = (state, action) => {
switch(action.type) {
case 'setActive':
return { ...state, active: action.value };
case 'setComplete':
return { ...state, complete: action.value };
default:
return state;
}
}
const ListItem = ({ item }) => {
const [state , dispatch] = useReducer(reducer, { active: item.active, complete: item.complete });
useEffect(() => {
if(state.active !== item.active || state.complete !== item.complete) {
fetch(`http://my-api/items/${item.id}`, {
method: 'PUT',
body: { item: state },
});
}
}, [state]);
const updateActive = (e) => {
dispatch({ type: 'setActive', value: e.target.checked });
}
const updateComplete = (e) => {
dispatch({ type: 'setComplete', value: e.target.checked });
}
return (
<li>
Active:
<input type="checkbox" checked={state.active} onChange={updateActive} />
Complete:
<input type="checkbox" checked={state.complete} onChange={updateComplete} />
</li>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment