Last active
November 11, 2017 17:21
-
-
Save trueadm/4880c34dbf8af57a768ff5addb641550 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// How we do this now | |
class CounterComponent extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
counter: 0, | |
}; | |
this._divRef = null; | |
this.increment = this.increment.bind(this); | |
} | |
increment() { | |
this.setState(state => ({ | |
counter: state.counter + 1, | |
})); | |
} | |
componentDidUpdate() { | |
this._divRef.color = this.props.color; | |
} | |
render() { | |
return ( | |
<div ref={divRef => this._divRef = divRef} onClick={this.increment}> | |
Count: {#state.counter} | |
</div> | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// How we could do this with React.Provider | |
// inspiration from Redux + Reason React | |
function counterReducer(action, state) { | |
switch (action) { | |
case "INCREMENT": { | |
return React.updateState({...state, {counter: counter + 1}}); | |
} | |
} | |
} | |
// a normal functional component | |
function CounterComponent(props) { | |
return ( | |
<React.Provider | |
initialState={() => ({ | |
counter: 0, | |
divRef: React.createRef(), | |
})} | |
reducer={counterReducer} | |
didUpdate={state => { | |
state.divRef.color = props.color; | |
}} | |
> | |
{(state, reduce) => | |
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}> | |
Count: {state.counter} | |
</div> | |
} | |
</React.Provider> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An alternative instead of the above | |
const CounterProvider = React.createProvider((action, state) => { | |
switch (action) { | |
case "INCREMENT": { | |
return React.updateState({...state, {counter: counter + 1}}); | |
} | |
} | |
}); | |
// a normal functional component | |
function CounterComponent(props) { | |
return ( | |
<CounterProvider | |
initialState={() => ({ | |
counter: 0, | |
divRef: React.createRef(), | |
})} | |
didUpdate={state => { | |
state.divRef.color = props.color; | |
}} | |
> | |
{(state, reduce) => | |
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}> | |
Count: {state.counter} | |
</div> | |
} | |
</CounterProvider> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// An alternative instead of the above | |
const counterState = React.createStateReducer((action, state) => { | |
switch (action) { | |
case "INCREMENT": { | |
return React.updateState({...state, {counter: counter + 1}}); | |
} | |
} | |
}); | |
// a normal functional component | |
function CounterComponent(props) { | |
return counterState({ | |
initialState: () => ({ | |
counter: 0, | |
divRef: React.createRef(), | |
}), | |
didUpdate: state => { | |
state.divRef.color = props.color; | |
}, | |
render(state, reduce) { | |
return ( | |
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}> | |
Count: {state.counter} | |
</div> | |
); | |
} | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// add a new component API, but suffers the same issues before in regards to folding | |
const CounterComponent = React.createReducerComponent({ | |
initialState: (props) => ({ | |
counter: 0, | |
divRef: React.createRef(), | |
}), | |
reducer: (action, state) => { | |
switch (action) { | |
case "INCREMENT": { | |
return React.updateState({...state, {counter: counter + 1}}); | |
} | |
} | |
}, | |
didUpdate: (props, state) => { | |
state.divRef.color = props.color; | |
}, | |
render: (props, state, reduce, context) => ( | |
<div ref={state.divRef} onClick={() => reduce("INCREMENT"))}> | |
Count: {state.counter} | |
</div> | |
), | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
So
handling-stage5.js
might look very much like how components in React are today, so what dohandling-stage2.js
,handling-stage3.js
orhandling-stage4.js
offer? Well, when it comes to component folding, it makes a big difference.Component folding works by recursively progressing through React component trees, starting with a "root" component. The "root" component's
props
object is completely unknown at that point. Having a completely unknown object makes it much harder to do ahead of time optimizations as we have to assume everything is abstract until we find something that tells us something is "concrete". Concrete values allow us to statically resolve code ahead of time. Each time we come to a child component of the root that we can't fold (we call this a "bail out") we have to start a new tree, using the component that we couldn't fold as a root. That means, theprops
of this component start of as unknown objects again.With
handling-stage2
,handling-stage3.js
andhandling-stage4
,Providers
do not have a render, but rather their children operate in the closure of the parent – allowing us to continue using the evaluatedprops
of the parent – meaning far less bailing out will occur.