Return JSX from function

2019-07-15 01:51发布

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!

4条回答
Anthone
2楼-- · 2019-07-15 02:07

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.

查看更多
Juvenile、少年°
3楼-- · 2019-07-15 02:10

Just change this function with map arrow function 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];
        }
      })
      Object.keys(toggles).forEach(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>
          ))
        );
      }
  }
查看更多
一纸荒年 Trace。
4楼-- · 2019-07-15 02:18

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>
      })
    );
  }
}
查看更多
劫难
5楼-- · 2019-07-15 02:25

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];
})
查看更多
登录 后发表回答