Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return JSX from function

I have a a component that needs to check for multiple options and return based on those options. Therefore I have created an outside function that is called in my component return statement to determine the format that will be returned:

render() {
    const { policy } = this.props;
    let deployment = policy.Deployment;
    let value = policy.value;
    let policyLegend = deployment.policyLegend;
    let policyObj = this.valueToPolicy(policyLegend, value);
    console.log(policyObj);
    if(policy.name == "SP4") {
      policyLegend[1].values = this.formatSp4Firmware(policyLegend[1]);
      return (
        <div>
          <Form onSubmit={ (event) => this.handleSubmit(event, this.props) }>
            {
              policyLegend.map((policy) => {
                return (
                  <div key={ policy.id }>
                    <h3>{ policy.displayName }</h3>
                    { this.renderSp4Policies(policy) }
                  </div>
                );
              })
            }
            <Button name={ 'Submit' } type='submit'>Submit</Button>
            <Button onClick={ this.props.onCancel }>Cancel</Button>
          </Form>
        </div>
      )
    } 
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

renderSp4Policies(policy) {
    if(policy.displayName == "Firmware Options") {
      let firmwareDropdownNames = this.formatFirmawareDropdownNames(policy);
      let toggles = policy.values[0][Object.keys(policy.values[0])];
      let toggleOptions = []
      Object.keys(toggles).map(toggle => {
      	if(typeof(toggles[toggle]) == "boolean"){
          var obj = {};
          obj[toggle] = toggles[toggle];
      		toggleOptions.push(obj);
        }
      })
      return (
        toggleOptions.map(toggleOption => {
          let toggleName = Object.keys(toggleOption).toString();
          return (
            <Form.Field key={ toggleName }>
              <label>{ toggleName }</label>
              <Checkbox toggle />
            </Form.Field>
          )
        })
      )
    } else {
        return (
          policy.values.map(value => {
            return(
              <Form.Field key={ value.name }>
                <label>{ value.displayName || value.name }</label>
                <Checkbox toggle />
              </Form.Field>
            )
          }
        )
      )
    }
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

EDIT

I have applied some of the answers given with moderate success.

Within renderSp4Policies what is being returned in the else statement displays, but the beginning if(policy.displayName == "Firmware Options") returns nothing.

Appreciate all advice, thank you in advance!

like image 609
salols Avatar asked Dec 05 '17 16:12

salols


People also ask

How do I use JSX in react?

JSX stands for JavaScript XML, a coding standard that allows you to use JavaScript expressions and other HTML features inline. Using JSX, you can create a function and return a set of JSX elements to a variable, and that variable used is to render the elements inside the render () function in React.

How do I execute an expression in JSX?

The expression can be a React variable, or property, or any other valid JavaScript expression. JSX will execute the expression and return the result: Execute the expression 5 + 5:

What is the use of JSX?

JSX is an extension of the JavaScript language based on ES6, and is translated into regular JavaScript at runtime. Get Certified! Complete the React modules, do the exercises, take the exam and become w3schools certified!! With JSX you can write expressions inside curly braces { }.

How to return HTML from JavaScript render?

Or you can return HTML inside JavaScript logic (such as if-else cases): render () { if (true) { return <p>YES</p>; } else { return <p>NO</p>; } } I won't go into further details of JSX, but make sure that you consider the following rules while writing JSX:


3 Answers

Your map function doesn't return anything:

policy.values.map(value => {
            <Form.Field key={ value.name }>
              <label>{ value.displayName || value.name }</label>
              <Checkbox toggle />
            </Form.Field>
          } 

When using an arrow function block {} you should add an explicit return statement:

policy.values.map(value => {
            return(<Form.Field key={ value.name }>
              <label>{ value.displayName || value.name }</label>
              <Checkbox toggle />
            </Form.Field>)
          }

Edit
As a followup to your comment.

As for the first if statement, don't use a forEach, use a map. same as you did in the second if statement (don't forget the return!)

renderSp4Policies(policy) {
  if (policy.displayName == "Firmware Options") {
    let toggles = policy.values[0][Object.keys(policy.values[0])];
    Object.keys(toggles).forEach(toggle => {
      if (typeof (toggles[toggle]) !== "boolean") {
        delete toggles[toggle];
      }
    })
    return (
      Object.keys(toggles).map(toggle => {
        return (
          <Form.Field key={toggle}>
            <label> {toggle} </label>
            <Checkbox toggle />
          </Form.Field>
        );
      })
    )
  } else {
    return (
      policy.values.map(value => {
        <Form.Field key={value.name}>
          <label>{value.displayName || value.name}</label>
          <Checkbox toggle />
        </Form.Field>
      })
    );
  }
}
like image 188
Sagiv b.g Avatar answered Oct 22 '22 16:10

Sagiv b.g


It seems like many people already did really well to help you fix your problem and explain it with details. But don't forget to follow the new concept of Component-Based architecture that React has introduced. So as a best practice you can write it this way:

import React, {Component} from "react";

import Sp4Policies from "./sp4Policies";

class MyComponent extends Component {
  render() {
    const { policy } = this.props;
    let deployment = policy.Deployment;
    let value = policy.value;
    let policyLegend = deployment.policyLegend;
    let policyObj = this.valueToPolicy(policyLegend, value);
    console.log(policyObj);
    if(policy.name == "SP4") {
      policyLegend[1].values = this.formatSp4Firmware(policyLegend[1]);
      return (
        <div>
          <Form onSubmit={ (event) => this.handleSubmit(event, this.props) }>
            {
              policyLegend.map((policy) => {
                return (
                  <div key={ policy.id }>
                    <h3>{ policy.displayName }</h3>
                    <Sp4Policies policy={policy} />
                  </div>
                );
              })
            }
            <Button name={ 'Submit' } type='submit'>Submit</Button>
            <Button onClick={ this.props.onCancel }>Cancel</Button>
          </Form>
        </div>
      )
    } 
  }
}

and a separate file:

import React, {Component} from "react";

class Sp4Policies extends Component {
  render() {
     const policy = this.props.policy;

     if (policy.displayName == "Firmware Options") {
       return (
         policy.values.map(value => (
           <Form.Field key={ value.name }>
             <label>{ value.displayName || value.name }</label>
             <Checkbox toggle />
           </Form.Field>
        ))
       );
     }

     return (
       let toggles = policy.values[0][Object.keys(policy.values[0])];
       Object.keys(toggles).forEach(toggle => {
         if(typeof(toggles[toggle]) !== "boolean"){
             delete toggles[toggle];
         }
       })
       Object.keys(toggles).map(toggle => {
         return(
           <Form.Field key={ toggle }>
             <label> { toggle } </label>
             <Checkbox toggle />
           </Form.Field>
         );
       })
     );
  }
}

export default Sp4Policies;

this makes your code clean and it ensures separation of concerns between your components. And of course you can still separate it even further.

like image 1
bigfanjs Avatar answered Oct 22 '22 16:10

bigfanjs


I run into this quite a bit and didn't just realize why this works until now. In your renderSp4Policies function, you're mapping through keys on the second line that has Object.keys(toggles).forEach(toggle => {. Inside that block you're returning elements and that instruction you're running is keeping track of that and generating an array. Once it's done, you're not doing anything with the array, so you have to add a return statement so the function returns the generated array of JSX elements:

return Object.keys(toggles).map(toggle => {
    return(
      <Form.Field key={ toggle }>
        <label> { toggle } </label>
        <Checkbox toggle />
      </Form.Field>
    );
  });

Also as Sag1v says, the line that has policy.values.map, you're not returning inside that loop. So you have to change:

policy.values.map(value => (
  return (
    <Form.Field key={ value.name }>
      <label>{ value.displayName || value.name }</label>
      <Checkbox toggle />
    </Form.Field>
  );
));

Edit

After our discussion in chat, I wanted to update my answer to reflect the proper changes.

The first Object.keys call that determines which keys should be saved and which shouldn't wasn't returning new data after every iteration so it was just making an empty array. forEach was also being used but that doesn't return a new array. After changing forEach to map and adding some return statements, it would create a new array so the second loop that follows would be able to run:

var toggleOptions = Object.keys(toggles).map(toggle => {
  if (typeof (toggles[toggle]) !== "boolean") {
    return delete toggles[toggle];
  }
  return toggles[toggle];
})
like image 3
bwalshy Avatar answered Oct 22 '22 16:10

bwalshy