Vs.

Component Properties

Declaring a local property

Since JSX is both javascript and template in one file, we do not need to create a separate file to manage properties. In React a property in a component is a variable that's been initialized inside the component function body.

Ember

// my-component.js
import Component from '@glimmer/component';
export default class MyComponent extends Component {
  value = 100;
}

<!-- my-component.hbs -->
<p>Value: {{this.value}}</p>

React

// MyComponent.jsx
export default function MyComponent() {
  let value = 100;
  return(<p>Value: {value}</p>)
}

This is where we start to see the benefits of Jsx since everything about one component is stored in one file.

Actions / Component Functions

In Ember, we define actions in component files using the @action decorator, in React there is no need, all functions can be considered actions. Calling the function is similar, we assign it via attributes.

Ember

// my-component.js
import Component from '@glimmer/component';
import { action } from '@ember/object';

export default class MyComponent extends Component {

  @action log() {
    console.log('Log called');
  }
}

{!-- my-component.hbs -}}
<button type="button" {{on "click" this.log}}>
  Log
</button>

React

// MyComponent.tsx
export default function MyComponent() {
  const log = () => console.log('Log called');

  return (
    <button type="button" onClick={log()}>
      Log
    </button>
  }
}

Updating the state of a local property

React hooks are a way of updating the state to indicate that we need to re-render the component, similar to the @tracked attribute.

For this example, we will use the useState hook to keep track of our local state.

Ember

// my-component.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class MyComponent extends Component {
  @tracked count = 0;

  @action increment() {
    this.count++;
  }
}

{{!-- my-component.hbs --}}
<p>Count: {{this.count}}</p>
<p>
  <button type="button" {{on "click" this.plusOne}}>
    Increment Count
  </button>
</p>

React

// MyComponent.jsx
import { useState } from "react";

export default function MyComponent() {
  let [count, setCount] = useState(0);

  // We can also declare a location function to save clutter
  return (
    <>
      <p>Count: {count}</p>
      <p>
        <button type="button" onClick={setCount(count + 1)}>
          Increment Count
        </button>
      </p>
    </>
  );
}

Computed Get Method

In Ember, we use native javascript get combined with the @computed decorator to

Ember

// my-component.js
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { computed, set } from '@ember/object';

export default class MyComponent extends Component {

  @computed('args.firstName', 'args.lastName')
  get fullName() {
    return `${this.args.firstName} ${this.args.lastName}`;
  }
}
{{!-- my-component.hbs --}}
<p>{{this.fullName}}</p>

React

// MyComponent.jsx
export default function MyComponent({ firstName, lastName }) {
	const fullName = `${firstName} ${lastName}`;

	return (<p>{fullName}</p>)
}

React will re-render the entire component each time a parameter is changed, this is good for simplicity. The React docs have a section on Keeping Components Pure, this is a good resource to learn about how React handles updates.

Previous
Template Syntax