I am trying to create a HOC using Context and I am getting Uncaught TypeError: n.children is not a function
Here is the basic code
index.js:
import { render } from 'preact';
import MyProvider from 'context';
import Button from 'button';
render(
<MyProvider color="red">
<Button/>
</MyProvider>,
target
);
context.js
import { Component, createContext } from 'preact';
const context = createContext();
export default class MyProvider extends Component {
render() {
const { children, ...value } = this.props;
return (
<context.Provider value={value}>{children}</context.Provider>
);
}
}
// this is the part that is faling
export const withContext = (WrappedComponent) => {
return class ContextConsumer extends Component {
render() {
return (<context.Consumer><WrappedComponent /></context.Consumer>);
}
}
}
button.js
import { Component } from 'preact';
import { withContext } from 'context';
class Button extends Component {
render() {
return (
<button>test</button>
);
}
}
export default withContext(Buttonn);
I also tried withContext like this
export const withContext = (WrappedComponent) => {
return class ContextConsumer extends Component {
render() {
return (<context.Consumer><WrappedComponent /></context.Consumer>);
}
}
}
Consumer is a render prop so your component should look like:
<Consumer>{(ctx) => <Component ctx={ctx} {...this.props} />}</Consumer>
The error message sais it expects the children to be a function
Hi @JoviDeCroock,
Thanks for getting back. This was actually one of the first things I tried.
export const withContext = (WrappedComponent) => {
return <context.Consumer>{(ctx) => <WrappedComponent ctx={ctx} {...this.props} />}</context.Consumer>
}
but this gave preact.js?10a9:1 Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('[object Object]') is not a valid name.
This however does seem to work.
export const withContext = (WrappedComponent) => {
return class ContextConsumer extends Component {
render() {
return <context.Consumer>{(ctx) => <WrappedComponent ctx={ctx} {...this.props} />}</context.Consumer>
}
}
}
This also used to work in v8 with preact-context
export const withContext = OriginalComponent => props => (
<context.Consumer render={ctx => <OriginalComponent {...ctx} {...props} />} />
);
Works for me with Preact X, has to be something else on your side: https://codesandbox.io/s/hidden-https-04wf2
ok will look into it.
Are these not equivalent? I was trying the former so wasn't getting success as a render prop.
return <context.Consumer render={(ctx) => <WrappedComponent ctx={ctx} {...this.props} />}></context.Consumer>
return <context.Consumer>{(ctx) => <WrappedComponent ctx={ctx} {...this.props} />}</context.Consumer>
These are not equivalent, in the former you are relying on the render function of Consumer to be this:
render() {
return this.props.render(context)
}
while in the latter you are relying on this implementation:
render() {
return this.props.children(context)
}
oh, your codesandbox works for me as well. What I was saying above is that this does not work
export const withContext = (WrappedComponent) => {
return <context.Consumer>{(ctx) => <WrappedComponent ctx={ctx} {...this.props} />}</context.Consumer>
}
It seems that just a simple function like this should work, no?
Because that is not a HOC, that's a regular function for your case you'd need to do this:
export const wrapWithContext = (WrappedComponent) => {
return (props) => <context.Consumer>{(ctx) => <WrappedComponent ctx={ctx} {...props} />}</context.Consumer>
}
You could also use the hooks API which allows you to just do this const value = useContext(context)
ok great, it was my use of render={ causing issues. Like I mentioned this worked in Preact 8 using preact-context
Thanks for the help looking into this, hopefully this can help others making the transition.
Most helpful comment
These are not equivalent, in the former you are relying on the render function of Consumer to be this:
while in the latter you are relying on this implementation: