-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] New context API #963
Conversation
my context api realization create-context.js import { Component } from "./component";
import { extendComponent } from "./util";
export function createContext(value) {
var context = {
default: value
}
function Provider(p, c) {
Component.call(this, p, c);
this.c = [];
this.p = this.p.bind(this);
this.u = this.u.bind(this);
}
extendComponent(Provider, {
p(subscriber) {
this.c.push(subscriber);
return this.props.value;
},
u(subscriber) {
this.c = this.c.filter(function (i) { return i !== subscriber; });
},
getChildContext() {
var provider = {
push: this.p,
pop: this.u,
context: context,
};
let providers = this.context.providers;
if (providers) {
providers.push(provider);
} else {
providers = [provider];
}
return { providers };
},
componentWillReceiveProps(nextProps) {
if (this.props.value !== nextProps.value) {
this.c.forEach(function (subscriber) {
subscriber(nextProps.value);
});
}
},
render() {
return this.props.children && this.props.children[0];
}
});
function Consumer(p, c) {
Component.call(this, p, c);
this.updateContext = this.updateContext.bind(this);
if (c.providers) {
for (var i = c.providers.length - 1; i >= 0; i--) {
var provider = c.providers[i];
if (provider.context === context) {
var value = provider.push(this.updateContext);
this.state = {
value: value,
};
this.popSubscriber = provider.pop;
break;
}
}
}
}
extendComponent(Consumer, {
updateContext(val) {
this.setState({ value: val });
},
componentWillUnmount() {
if (this.popSubscriber) {
this.popSubscriber(this.updateContext);
}
},
render() {
return this.props.children && this.props.children[0](this.state.value);
}
});
context.Provider = Provider
context.Consumer = Consumer
return context;
} util.js export function extendComponent(obj, prop) {
function __() { this.constructor = obj; }
__.prototype = Component.prototype
obj.prototype = new __();
extend(obj.prototype, prop)
} test/test.html <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="../dist/preact.js"></script>
<!-- <script src="../node_modules/preact/dist/preact.dev.js"></script> -->
<title>Document</title>
</head>
<body>
<div id="app">
</div>
<script>
'use strict';
var h = preact.h;
var render = preact.render;
var Component = preact.Component;
const ThemeContext = preact.createContext({
background: 'red',
color: 'white'
});
const ContextMap = {
1: { background: 'red', color: 'white' },
2: { background: 'green', color: 'white' }
}
class App extends Component {
constructor() {
super()
this.state = {
map: 1
}
}
select() {
this.setState({
map: this.state.map === 1 ? 2: 1
})
}
render () {
return (
h("div", null,
h(ThemeContext.Provider, {value: ContextMap[this.state.map === 1 ? 2: 1]},
h(Header, {map: this.state.map})
),
h(ThemeContext.Provider, {value: ContextMap[this.state.map]},
h(Header, {map: this.state.map === 1 ? 2: 1})
),
h("button", {onClick: () => this.select()}, "测试")
)
);
}
}
class Header extends Component {
// shouldComponentUpdate() {
// return false
// }
render () {
return h(Title, this.props, "Hello React Context API")
}
}
class Title extends Component {
render () {
return h(ThemeContext.Consumer, null,
context => h(this.props.map === 1 ? "h1": "h2", {style: {background: context.background, color: context.color}},
this.props.children
)
)
}
}
render(
h(App),
document.getElementById('app')
);
</script>
<script src="../devtools.js"></script>
</body>
</html> |
@developit I think we can, will non-invasive react new api publishing it as a dedicated module. |
What is the status on this? Since I would love to make use of it, I do have an implementation here. It is in typescript and lacks some tests. @developit Since I mostly used the code here and wouldn't like to hijack anything, I am ok on moving my repository anywhere that would make sense and also giving ownership to either @jtmthf or @zeromake. All I want is to make use of this feature :) |
Having a closer look at it. If we do not always need to use
it looks like that this should be the case. @developit maybe it makes more sense to ditch context in favor of the new api. |
Just published preact-context with an implementation |
Thanks for your work! Are there any news on this? |
This can be used by overriding preact-compat in webpack-alias: resolve: {
alias: {
'react': path.resolve(__dirname, '../src/helpers/preact-compat'),
'react-dom': 'preact-compat'
}
} And in your
|
Good news: |
So, is the new context API already part of preact? https://github.com/valotas/preact-context is no longer needed? |
yup |
Proposing removing the reference to the `preact-context` library, as it confuses making people think that core preact doesn't support the new Context API, which according to #963 (comment), it does.
This PR is an implementation of React's proposed new context API for Preact. This implementation is built on top of the existing context API. React's corresponding PR is facebook/react#11818 and the RFC is reactjs/rfcs#2.
These are the following tasks and considerations I've identified that will need to be accomplished before merging.
Provider
without anyConsumer
's.