React Context: TypeError: render is not a function

2020-02-28 02:06发布

问题:

I'm trying to use React Context to pass a function to a nested child component, which effectively allows the child to update the parents state when pressed.

The problem is I seem to be getting an error 'TypeError: render is not a function. (In render(newValue), render is an instance of Array' and an error in my console reads: 'Warning: A context consumer was rendered with multiple children, or a child that isn't a function. A context consumer expects a single child that is a function. If you did pass a function, make sure there is no trailing or leading whitespace around it.'

I've looked around at this error and also at documentation but no answers seem to answer my question, I can't quite work out why this isn't working.

EDIT: I should add that there are multiple child components rendered, as they're built from an array of objects

Snippets:

Parent:

class Product extends Component {
    state = {
        selected_ind: 0
    };

    handleContextChange = selected_ind => {
        this.setState({selected_ind});
    };

    render() {
        const contextValue = {
            data: this.state,
            handleChange: this.handleContextChange
        };

        //Desconstruct props for ease of use
        const {
            attr_data,
            variant,
            product_name } = this.props;


        return (
                <Container>
                    <Heading>Product Options</Heading>
                    <IndexContext.Provider value={contextValue}>
                        <OptionTile
                            tileColor='grey'
                            onPress={ () => this.props.navigation.navigate('Variants', {
                                attr_data: attr_data,
                                selected_ind: this.state.selected_ind
                            })} //Replace with named function
                            option="Variant"
                            selected_ind={ this.state.selected_ind }
                            value={ selected_attr.name } />
                    </IndexContext.Provider>
                    <OptionTile
                        tileColor='grey'
                        option="Quantity"
                        value="1" />
                </Container>

Within OptionTile is the child I'd like to use the function within:

const VariantTile = (props) => {
    return (
        <IndexContext.Consumer>
            {({ handleChange }) => (
                <TouchableOpacity onPress={handleChange(props.index)}>
                    <AsyncImage
                        source={ props.img_src }
                        placeholderColor="#fafafa"
                        style={{ flex: 1, width: null, height: 200 }}
                    />
                    <Text>{ props.var_name }</Text>
                    <Text>{ props.price }</Text>
                    <Text>{ props.sku }</Text>
                </TouchableOpacity>
            )};
        </IndexContext.Consumer>
    )
};

And the context component is simple:

const IndexContext = React.createContext();

export default IndexContext;

回答1:

As the error states, <Consumer> should have the only child, and it should be a function. The error appears when it has multiple children, including text nodes.

; after embedded expression causes the problem. It's not a part of an expression, and making it a part of it would result in syntax error.

It should be:

<IndexContext.Consumer>
    {({ handleChange }) => (
        <TouchableOpacity onPress={handleChange(props.index)}>
            <AsyncImage
                source={ props.img_src }
                placeholderColor="#fafafa"
                style={{ flex: 1, width: null, height: 200 }}
            />
            <Text>{ props.var_name }</Text>
            <Text>{ props.price }</Text>
            <Text>{ props.sku }</Text>
        </TouchableOpacity>
    )}
</IndexContext.Consumer>