Dynamically render multiple buttons in react js from an array

Howdy, campers.

I’ve got a component that is dynamically rendering a series of buttons based on the contents of an array.

Really, it is a series of views that each display the name from the array and an accompanying button.

 <View>
          {this.props.rolesarray.map(function(object) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
              return (
                <View >
                <DisplayRoles key={object.id} data={object} />
                <Button title="this is a button"  />
                </View>
              );
            })}
        </View>

This works fine, but it would look a lot better if I just had a single button that just displayed the name from the array as the title of the button.

What I am struggling with at the moment is how to get the name of the person from the array to show up as the title on the button.

What concepts do I need to understand in order to do this?

Thanks!

Try having your loop generate buttons before the return statement. Store them to a variable. Then use JS injection after the return statement in between the view tags.

I have example code from a project at home, but I won’t be there for a couple hours. I will post it if nobody has helped before that.

1 Like

It’s hard to say without seeing the shape of your data, but is there are reason why you can’t do:

<Button title={ object.name } />

I guess I’m confused by what you mean by “name from the array”. Is the name part of the array or part of each element of the array? I’m assuming it’s the latter.

I have a render statement that has a loop before the return:

render() {
		let allOptions = this.props.spells.map((val, i) => this.props.selectMaker(val, i, this.props.type));

		return (
			<div>				
				<div className="my-custom-select">
					{allOptions}
				</div>				
			</div>
		);

My function selectMaker takes an array and returns JSX:

return(
  			<div key={val.name} className='selectable' onClick={this.handleClick} val={val.name} data={type} style={{paddingLeft:18, width:'100%'}}>
  			{val.name}
  			{bonus||conc||domain?' (':null}
			{domain?'D':null}
			{bonus?'B':null}
			{conc?'C':null}
			{bonus||conc||domain?')':null}
			</div>
  		)

If I understand your question, you should be able to do a similar thing with your array.

You’d think.

This returns the error “Invariant Violation: The title prop of a Button must be a string.”:

    <View>
          {this.props.rolesarray.map(function(object) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
              return (
               <View >
                <DisplayRoles key={object.id} data={object} />
                <Button title={ object.name }  />
                </View>
              );
            })}
          </View>

This returns the error “TypeError: undefined is not an object (evaluating ‘object.name.toString’).”:

      <View>
          {this.props.rolesarray.map(function(object) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
          return (
            <View >
            <DisplayRoles key={object.id} data={object} />
            <Button title={ object.name.toString }  />
            </View>
          );
        })}
      </View>

The array is just an array of names.

export class yourClass extends Component {

	render() {
		let element = this.props.rolesarray.map(function(object) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
              return (
                <DisplayRoles key={object.id} data={object} />
                <Button title={ object.name }  />
              );
            })
		

		return (
			<View>
				{element}			
			</View>
		);
	}
}

The array is just an array of names.

So does it even have an id or name property? If not, maybe that’s the problem. The above code should work for an array of objects each with an id and a name property. An array of names would look something more like…

export class yourClass extends Component {

	render() {
		let element = this.props.rolesarray.map(function(val, i) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
              return (
                <DisplayRoles key={"object"+i} data={val} />
                <Button title={ val }  />
              );
            })
		

		return (
			<View>
				{element}			
			</View>
		);
	}
}

Would need more info to help further.

Here is the full component this is sitting in:

  class Roles extends React.Component {

 constructor(props) {
    super(props);
    this.editRoles = this.editRoles.bind(this);
  };


render() {
  return (
  <View

    style={{
      flexDirection: 'column',
      minHeight: 100,
      padding: 20,
      justifyContent:'space-between',
      color: 'white',
    }}>


    <Text style={{color: 'blue'}}>What role(s) must test this requirement?</Text>
    <TextInput
    style={{height: 40, borderColor: 'gray', borderWidth: 1, margin: 2}}

    value={this.props.rolesText1}

    onChangeText={this.props.onClick}
    />

    <Button
      onPress={this.props.onClick2}
      color={this.props.backgroundcolor}
      disabled={this.props.disabled}
      title="Accept Role"
      />


      <View>

      {this.props.rolesarray.map(function(object) { // for each element in the Roles array, display it https://stackoverflow.com/questions/37997893/promise-error-objects-are-not-valid-as-a-react-child
          return (
            <View >
            <DisplayRoles key={object.id} data={object} />
            <Button title={ "this is a button" }  />
            </View>
          );
        })}

        )}

      </View>
  </View>
  );
}

}

Right now,

DisplayRoles key={object.id} data={object}
and

Button title={ “this is a button” }
are working just fine.

The object does indeed have an id. So if you add “Bob” to position zero in the array and “Jane” to position 1, it renders two elements just fine: “Bob” plus a button that says “this is a button” and “Jane” plus a button that says “this is a button.”

Trying to get it so that it just returns two buttons in the above scenario, one that just says “Bob” and the other that just says “Jane”

Honestly, I could just scrap the whole button idea and make the DisplayRoles element clickable. But I really would like to know why this is not working!