0

I have a react component, which renders some block with another component based on the state. How could I render both HTML-like JSX and component inside of JS?

class Feedback extends Component {
constructor(props) {
    super(props);
    this.state = {
        storeInputShow: true
    };
}
render() {
    return (
        <div>
            { this.state.storeInputShow ?
                <div className="form_field" style={{ marginBottom: '4px' }}>
                    <Text textTag="div">
                        Select shop
                    </Text>
                </div>
                <Autocomplete
                    items={this.state.storeList}
                    shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
                    getItemValue={item => item.label}
                    renderItem={(item, highlighted) =>
                        <div
                            key={item.id}
                            style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
                        >
                            {item.label}
                        </div>
                    }
                    value={store}
                    onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
                    onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
                    inputPlaceholder="Shop"
                    wrapperStyle={selectWrapperStyle}
                    menuStyle={selectMenuStyle}
                />
                : null
            }
        </div>
    );
}

Right now the error is the following:

SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag

at the <Autocomplete tag.

3 Answers 3

2

The error is self-explanatory, you should wrap both components inside one to make your conditional work.

<div>
    <div className="form_field" style... />
    <Autocomplete items={this.state.storeList} should... />
</div>

You could use a React.Fragment instead of <div />

BONUS: You could use the following syntax to remove the end null case

<div>
    { this.state.storeInputshow && <YourComponents /> }
</div>

That way you will only render if storeInputShow is available in the state without needing to return null if not.

Sign up to request clarification or add additional context in comments.

4 Comments

I'm assuming your using some plugin for <>, to transform to <React.Fragment>,. to make it so most Editors & transpiler settings work, it might be best showing your example with the <React.Fragment> tag.
@Keith good point, just updating it to <div />, that way there's no confusion
Yeah, good idea. For those reading this, the advantage of the <React.Fragment> it doesn't create an additional DOM element, this might be important if the DOM ordering is important for CSS etc.
@AlexSanchez thank you, it works fine. Also your additional bonus is really handy
0

You can't put if into a return, but you can put a variable.

class Feedback extends Component {
constructor(props) {
    super(props);
    this.state = {
        storeInputShow: true
    };
}
render() {

    let form;

    if (this.state.storeInputShow)
        form = <div className="form_field" style={{ marginBottom: '4px' }}>
                    <Text textTag="div">
                        Select shop
                    </Text>
                </div>
                <Autocomplete
                    items={this.state.storeList}
                    shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
                    getItemValue={item => item.label}
                    renderItem={(item, highlighted) =>
                        <div
                            key={item.id}
                            style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
                        >
                            {item.label}
                        </div>
                    }
                    value={store}
                    onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
                    onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
                    inputPlaceholder="Shop"
                    wrapperStyle={selectWrapperStyle}
                    menuStyle={selectMenuStyle}
                />;


    return (
        <div>{ form }</div>
    );

2 Comments

That will just give you the same error,.. Using React.Fragment like Alex says is the correct answer.
It's always better to deal with the problem without data mutations, but thank you for your comment
0

Problem in your code is, with in the if-condition, for true case you are returning two elements(,) but in JSX it expects every return to be one element(which can have any number of child's). So just wrap your elements in if-condition with wrapper.

class Feedback extends Component {
constructor(props) {
    super(props);
    this.state = {
        storeInputShow: true
    };
}
render() {
    return (
        <div>
            { this.state.storeInputShow ?
                <div>
                <div className="form_field" style={{ marginBottom: '4px' }}>
                    <Text textTag="div">
                        Select shop
                    </Text>
                </div>
                <Autocomplete
                    items={this.state.storeList}
                    shouldItemRender={(item, value) => item.label && item.label.toLowerCase().indexOf(value.toLowerCase()) > -1}
                    getItemValue={item => item.label}
                    renderItem={(item, highlighted) =>
                        <div
                            key={item.id}
                            style={{ backgroundColor: highlighted ? '#eee' : '#ffffff', ...selectItemStyle }}
                        >
                            {item.label}
                        </div>
                    }
                    value={store}
                    onChange={e => this.setState({ store: e.target.value, storeId: e.target.id })}
                    onSelect={(store,storeCard) => this.setState({ store, storeId: storeCard.id })}
                    inputPlaceholder="Shop"
                    wrapperStyle={selectWrapperStyle}
                    menuStyle={selectMenuStyle}
                />
                </div>
                : null
            }
        </div>
    );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.