Skip to content

Instantly share code, notes, and snippets.

@trueadm
Last active July 14, 2020 06:41
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save trueadm/198ae6902d2c5459e91a8e571b561b40 to your computer and use it in GitHub Desktop.
Save trueadm/198ae6902d2c5459e91a8e571b561b40 to your computer and use it in GitHub Desktop.
// Option C:
// this implementation has a small amount of overhead compared to (a) and (b)
const React = require('react');
const counterState = React.createStateReducer({
initialState: props => ({
counter: 0,
divRef: React.createRef(),
}),
reducer: (action, state) => {
switch (action) {
case "INCREMENT": {
return React.updateState({counter: state.counter + 1});
}
}
},
didUpdate: (props, state) => {
state.divRef.style.color = props.color;
},
});
function CounterComponent(props) {
return counterState(props, (state, reduce) =>
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}>
Count: {state.counter}
</div>
);
}
module.exports = CounterComponent;
// Option D:
// has the least overhead of all the implementations in Safari
const React = require('react');
function initialState(props) (
return {
counter: 0,
divRef: React.createRef(),
}
)
function reducer(action, state) (
switch (action) {
case "INCREMENT": {
return React.updateState({counter: state.counter + 1});
}
}
)
function didUpdate(props, state) {
state.divRef.style.color = props.color;
}
function CounterComponent(props) {
return React.createStateReducer(
{props, initialState, reducer, didUpdate},
(state, reduce) => (
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}>
Count: {state.counter}
</div>
)
);
}
module.exports = CounterComponent;
// Option E:
// has the least overhead of all the implementations in Chrome/Node/Firefox
const React = require('react');
const CounterComponent = {
initialState(props) {
return {
counter: 0,
divRef: React.createRef(),
}
},
reducer(action, state) (
switch (action) {
case "INCREMENT": {
return React.updateState({counter: state.counter + 1});
}
},
didUpdate(props, state) {
state.divRef.style.color = props.color;
},
render(props, state, reduce) {
return (
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}>
Count: {state.counter}
</div>
);
}
}
module.exports = CounterComponent;
// Option A:
// this implementation has quite a bit of overhead in all browsers due to the
// function creation in the functional component
const React = require('react');
const counterState = React.createState();
const counterReducer = (action, state) => {
switch (action) {
case "INCREMENT": {
return React.updateState({counter: state.counter + 1});
}
}
};
function CounterComponent(props) {
return counterState({
initialState: () => ({
counter: 0,
divRef: React.createRef(),
}),
didUpdate: state => {
state.divRef.style.color = props.color;
},
reducer: counterReducer,
render(state, reduce) {
return (
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}>
Count: {state.counter}
</div>
);
}
});
}
module.exports = CounterComponent;
// Option B:
// this implementation has quite a bit of overhead in all browsers due to the
// function creation in the functional component
const React = require('react');
const counterState = React.createStateReducer((action, state) => {
switch (action) {
case "INCREMENT": {
return React.updateState({counter: state.counter + 1});
}
}
});
function CounterComponent(props) {
return counterState({
initialState: () => ({
counter: 0,
divRef: React.createRef(),
}),
didUpdate: state => {
state.divRef.style.color = props.color;
},
render(state, reduce) {
return (
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}>
Count: {state.counter}
</div>
);
}
});
}
module.exports = CounterComponent;
@MatejBransky
Copy link

MatejBransky commented Nov 11, 2017

Maybe a small mistake but line 8 at example-a.js and line 7 at example-b.js:

return React.updateState({...state, {counter: state.counter + 1}});

or where do you get that counter?

@trueadm
Copy link
Author

trueadm commented Nov 11, 2017

@matejmazur well spotted!

@tizmagik
Copy link

Interesting! Wondering, do you need the return React.updateState({...})? Would you ever return anything else?

@trueadm
Copy link
Author

trueadm commented Nov 12, 2017

@tizmagik, there might be different types of update, like async updates etc. It opens up more routes in the future.

@bvaughn
Copy link

bvaughn commented Nov 13, 2017

Disclaimer: I'm super jet-lagged and my brain is only half working at the moment, but since Dom asked me to take a look- I think I like option-e the best. 😄

I do have a thought or two:

  • example-a: I'm curious why React.createState returns a function instead of a state? Doesn't seem obvious why that's necessary since it doesn't accept any arguments. Is it just to make it more comparable to the others?
  • example-e: Does the CounterComponent function even need to exist? All it does is relay props. Could reduce boilerplate a little with just:
modules.exports = React.createReducerComponent(counterComponent);

I'd also like to learn a little more about the constraints of didUpdate. What types of things- other than tweaking refs- is it okay to do in this lifecycle? (Is there anything that's safe to do in eg componentDidMount that it won't be safe to do in didUpdate without causing deopts?)

@trueadm
Copy link
Author

trueadm commented Nov 13, 2017

@bvaughn I've updated example E after speaking with Dan. I think example A and B are probably going to be no goes because of the overhead they add in the render phase. The naming of createState() was also probably not the right name for this method.

The reason I went with different lifecycle names was purely to avoid confusion with existing ones – as the arguments passed wouldn't match up. I'm not fussed on name, I just didn't want to create more confusion. We could also infer async by default with some of them, to help the async story more (rather than sync like they are now).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment