Binding buttons in SPFx

When writing a react based SPFx application one has to make a note that ES6 React.Component doesn’t auto bind methods to itself.

Hence it’s required to manually bind and the following are two ways to do it.

Method 1

onClick={this.addButtonClicked.bind(this)}

import * as React from 'react';

import { Stack, IStackProps, IStackStyles } from 'office-ui-fabric-react/lib/Stack';
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
import { IIconProps } from 'office-ui-fabric-react/';

import { ITestComponentState } from './ITestComponentState';
import { ITestComponentProps } from './ITestComponentProps';

//Stack related styles
const outerStackTokens = {
    childrenGap: 50
};
const addFriendIcon: IIconProps = { iconName: 'Add' };

let outerStackStyles: Partial<IStackStyles> = {};
let innerStackColumnProps: Partial<IStackProps> = {};

export default class TestComponent extends React.Component<ITestComponentProps, ITestComponentState> {
    constructor(props: ITestComponentProps) {
        super(props);
        this.state = {
            items: []
        };
    }
  
    public render(): React.ReactElement<{}> {
        return (
            <div>
                <Stack horizontal tokens={outerStackTokens} styles={outerStackStyles}>
                    <Stack verticalAlign="start" {...innerStackColumnProps}>
                        <Stack.Item align="start" >
                            <ActionButton iconProps={addFriendIcon} onClick={this.addButtonClicked.bind(this)} allowDisabledFocus disabled={this.state.sortItems.length >= 10 ? true : false} >Add Item</ActionButton>
                        </Stack.Item>
                    </Stack>
                </Stack>
            </div>
        );
    }

    private addButtonClicked(event?: React.MouseEvent<HTMLButtonElement>) {
        let itemsOnAdd = this.state.items;
        let itemTitle = "Item " + (this.state.items.length + 1);
        itemsOnAdd.push({ title: itemTitle });
        this.setState({ items: itemsOnAdd });
    }
}

Method 2

this.addButtonClicked = this.addButtonClicked.bind(this);

import * as React from 'react';

import { Stack, IStackProps, IStackStyles } from 'office-ui-fabric-react/lib/Stack';
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
import { IIconProps } from 'office-ui-fabric-react/';

import { ITestComponentState } from './ITestComponentState';
import { ITestComponentProps } from './ITestComponentProps';

//Stack related styles
const outerStackTokens = {
    childrenGap: 50
};
const addFriendIcon: IIconProps = { iconName: 'Add' };

let outerStackStyles: Partial<IStackStyles> = {};
let innerStackColumnProps: Partial<IStackProps> = {};

export default class TestComponent extends React.Component<ITestComponentProps, ITestComponentState> {
    constructor(props: ITestComponentProps) {
        super(props);
        this.state = {
            items: []
        };
        this.addButtonClicked = this.addButtonClicked.bind(this);
    }
  
    public render(): React.ReactElement<{}> {
        return (
            <div>
                <Stack horizontal tokens={outerStackTokens} styles={outerStackStyles}>
                    <Stack verticalAlign="start" {...innerStackColumnProps}>
                        <Stack.Item align="start" >
                            <ActionButton iconProps={addFriendIcon} onClick={this.addButtonClicked} allowDisabledFocus disabled={this.state.sortItems.length >= 10 ? true : false} >Add Item</ActionButton>
                        </Stack.Item>
                    </Stack>
                </Stack>
            </div>
        );
    }

    private addButtonClicked(event?: React.MouseEvent<HTMLButtonElement>) {
        let itemsOnAdd = this.state.items;
        let itemTitle = "Item " + (this.state.items.length + 1);
        itemsOnAdd.push({ title: itemTitle });
        this.setState({ items: itemsOnAdd });
    }
}

React – Call function from HTML Tag with parameter

ReactSometimes we need to call a React function from HTML tags with parameters or arguments and following is the ES6 based way.

Here a button is calling a function updateName with argument newName to set a state which in turns changes the name being displayed.

import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'Kannan'
    };
  }

  updateName = (newName) =>{
    this.setState({
      name: newName
    })
  }

  render() {
    return (
      <div>
        <p>My Name is {this.state.name}.</p>
        <p>          
          <button onClick={this.updateName.bind(this,'Kannan Balasubramanian')}>Change the name</button><br/>
          <button onClick={()=>this.updateName('Kannan Balasubramanian!')}>Change the name again</button>
        </p>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

Do note that using this.updateName.bind() is the recommended way due to performance and efficiency concerns.

You can try the sample output here.