React components: Difference between revisions

From wikinotes
No edit summary
 
(36 intermediate revisions by the same user not shown)
Line 1: Line 1:
= Component Functions =
= Documentation =
<blockquote>
{| class="wikitable"
|-
| component docs || https://reactjs.org/docs/react-component.html
|-
| fragment docs || https://reactjs.org/docs/fragments.html
|-
| list docs ||
|-
| portal docs || https://reactjs.org/docs/portals.html
|-
|}
</blockquote><!-- Documentation -->
 
= Components =
<blockquote>
== Component Functions ==
<blockquote>
<blockquote>
<source lang="javascript">
<source lang="javascript">
function Description(props) {
function Description() {
     return (
     return (
         <h1>Description</h1>
         <h1>Description</h1>
         <p>{props.paragraph}</p>
         <p>{this.props.paragraph}</p>
     )
     )
}
}
</source>
</source>
<syntaxhighlight lang="html5">
<Description paragraph="a very long..." />
</syntaxhighlight>
</blockquote><!-- Functions -->
</blockquote><!-- Functions -->


= Component Classes =
== Component Classes ==
<blockquote>
<blockquote>
<source lang="javascript">
<source lang="javascript">
Line 17: Line 38:
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
     this.state = {name: "vaderd", id: 101}
     this.state = {name: props.name, id: props.id}
   }
   }


Line 30: Line 51:
}
}
</source>
</source>
<syntaxhighlight lang="html5">
<Employee name="vaderd" id="101" />
</syntaxhighlight>
</blockquote><!-- Component Classes -->
</blockquote><!-- Component Classes -->
</blockquote><!-- Components -->


= Parameters =
= Attributes =
<blockquote>
== this.props ==
<blockquote>
<blockquote>
Components are expressed as [[xml]] tags.<br>
Parameters are passed parameters using [[xml]] tag attributes.<br>
Parameters are passed parameters using [[xml]] tag attributes.<br>
Within the component, they are axposed as attributes on the <code>props</code> variable.
Within the component, they are axposed as attributes on the <code>this.props</code> variable.


<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
Line 46: Line 73:


<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
function Description(props) {
function Description() {
     return <p>hello, {props.name}</p>;  // <-- access props in component
     return <p>hello, {this.props.name}</p>;  // <-- access props in component
}
}
</syntaxhighlight>
</syntaxhighlight>
</blockquote><!-- Parameters -->
</blockquote><!-- Parameters -->


= Lifecycle Methods =
== this.state ==
<blockquote>
<code>this.state</code> is a special object property to store UI related info.<br>
The component will be re-rendered every time the <code>this.setState()</code> is called.
 
<syntaxhighlight lang="javascript">
class Thing extends React.Component {
    constructor(props) {
        super(props);
        this.state = { collapsed: false };
    }
 
    render() {
        if (this.state.collapsed) {
            <p>collapsed</p>
        } else {
            <p>expanded</p>
        }
    }
}
</syntaxhighlight>
 
<syntaxhighlight lang="javascript">
this.setState({ collapsed: false }) // good: update state
this.state = { collapsed: false }  // bad:
</syntaxhighlight>
</blockquote><!-- Element Variables -->
</blockquote><!-- Attributes -->
 
= Render Types =
<blockquote>
== Elements ==
<blockquote>
Generally, React requires that a single top-level html-element is returned by each component.
 
<syntaxhighlight lang="javascript">
class Person extends React.Component {
    render() {
        return (
            <table>
                <tr><th>...</th></tr>
                <tr><th>...</th></tr>
            </table>
        );
    }
}
</syntaxhighlight>
</blockquote><!-- Elements -->
 
== Lists ==
<blockquote>
<blockquote>
React components have methods to ''mount/unmount'' behaviours when the object is first created or destroyed.<br>
You may render() a list of elements to some compound types, like lists.<br>
These can set/unset timers to auto-update the object.
Each item requires a unique <code>key</code> so react can keep track of CRUD operations with list items.


Check out the [https://reactjs.org/docs/state-and-lifecycle.html tutorial].
<syntaxhighlight lang="javascript">


{{ TODO |
class ListItems extends React.Component {
Why can't the constructor/destructor be used? }}
    render() {
        var items = [
          {key: "a", text: "aaa"},
          {key: "b", text: "bbb"},
          {key: "c", text: "ccc"},
        ]
        return items.map((x) =>
          <li key={x.key}> // key={foo} lets react update changes
            {x.text}
          </li>
        );
    }
}


<source lang="javascript">
class MyList extends React.Component {
class Foo extends React.Component {
    render() {
  componentDidMount() { ... }
        return (
  componentWillUnmount() { ... }
            <ul>
            <ListItems />
            </ul>
    }
}
}
</source>
</syntaxhighlight>
</blockquote><!-- Lifecycle Methods -->
</blockquote><!-- Lists -->


= DOM Events =
== Fragments ==
<blockquote>
<blockquote>
You can subscribe to DOM events with callbacks similarly to [[javascript]].<br>
Fragments are a special wrapper type that allows you to return multiple top-level html-elements in one clump.<br>
except that events are in camelcase <br>
They do not need to be a homogenous collection of top-level elements.
and callbacks are defined as methods rather than strings.


See https://reactjs.org/docs/handling-events.html
You can use either of the following tags:
* <code><React.Fragment>...</React.Fragment></code>
* <code><>...</></code>


<source lang="javascript">
<syntaxhighlight lang="javascript">
class HelloWorld extends React.Component {
<table>
   sayHello() {
   <tr>
     console.log('hello')
     <Columns />  // <-- fragment with several items
  }
  </tr>
</table>
</syntaxhighlight>
 
<syntaxhighlight lang="javascript">
import React from 'react';


  render() {
function Columns(props) {
     return (
     return (
      <button onClick={() => this.sayHello()}>
        <React.Fragment>
         Say Hello
          <td>foo</td>
      </button>
          <td>bar</td>
          <td>baz</td>
         </React.Fragment>
     );
     );
  }
}
}
</source>
</syntaxhighlight>
</blockquote><!-- DOM Events -->
</blockquote><!-- Fragments -->


= Element Variables =
== Null (force no render) ==
<blockquote>
<blockquote>
You can configure a component to manage it's display based on a state variable.<br>
If a component's <code>render()</code> returns <code>null</code>,<br>
In this way, it fully encapsulates it's behaviour.
then it won't render anything, even if it is included in a page.


{{ TODO |
The official-docs use a debug-info as an example (you'd only want to render if in development environment).
untested }}


<source lang="javascript">
<syntaxhighlight lang="javascript">
const Button = styled.button
class DebugInfo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {debugEnabled: true};
    }
 
    render() {
        this.debugEnabled
          ? <p>debug info...</p>
          : null;
    }
}
</syntaxhighlight>
</blockquote><!-- Null (force no render) -->
</blockquote><!-- Return Types -->
 
= Lifecycle Methods =
<blockquote>
{{ NOTE |
An alternative to lifecycle methods is [[react hooks]]. }}


class MyButton extends React.Component {
React components have methods to ''mount/unmount'' behaviours when the object is first created or destroyed.<br>
  constructor(props) {
These can set/unset timers to auto-update the object.<br>
    super(props)
These behave similarly to constructor/destructor as hooks, except their events correspond with adding/removing them from the DOM.
    this.state = { collapsed: false }
    this.handleExpandClicked = this.handleExpandClicked.bind(this)
    this.handleCollapseClicked = this.handleCollapseClicked.bind(this)
  }


  handleExpandClicked() { this.setState({ collapsed: false }) }
Check out the [https://reactjs.org/docs/state-and-lifecycle.html tutorial] (might need to scroll to methods).
  handleCollapseClicked() { this.setState({ collapsed: true }) }
  render() {
    return button
  }


   button() {
<source lang="javascript">
    let button
class Foo extends React.Component {
    if (this.state.collapsed) {
   componentDidMount() { ... }     // runs after first 'render()'
      button = <Button onClick={this.handleExpandClicked} />
  componentWillUnmount() { ... }   // runs if object is removed from the DOM
    } else {
      button = <Button onClick={this.handleCollapseClicked} />
    }
    return button
  }
}
}
</source>
</source>
</blockquote><!-- Element Variables -->
</blockquote><!-- Lifecycle Methods -->

Latest revision as of 01:57, 11 December 2022

Documentation

component docs https://reactjs.org/docs/react-component.html
fragment docs https://reactjs.org/docs/fragments.html
list docs
portal docs https://reactjs.org/docs/portals.html

Components

Component Functions

function Description() {
    return (
        <h1>Description</h1>
        <p>{this.props.paragraph}</p>
    )
}
<Description paragraph="a very long..." />

Component Classes

class Employee extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name: props.name, id: props.id}
  }

  render() {
    return (
      <div>
        <h1>Name: {this.state.name}</h1>
        <h2>ID: {this.state.id}</h2>
      </div>
    );
  }
}
<Employee name="vaderd" id="101" />

Attributes

this.props

Parameters are passed parameters using xml tag attributes.
Within the component, they are axposed as attributes on the this.props variable.

ReactDOM.render(
    <Description name="Alex" />,         // <-- use component
    document.getElementById('root')
);
function Description() {
    return <p>hello, {this.props.name}</p>;  // <-- access props in component
}

this.state

this.state is a special object property to store UI related info.
The component will be re-rendered every time the this.setState() is called.

class Thing extends React.Component {
    constructor(props) {
        super(props);
        this.state = { collapsed: false };
    }

    render() {
        if (this.state.collapsed) {
            <p>collapsed</p>
        } else {
            <p>expanded</p>
        }
    }
}
this.setState({ collapsed: false }) // good: update state
this.state = { collapsed: false }   // bad:

Render Types

Elements

Generally, React requires that a single top-level html-element is returned by each component.

class Person extends React.Component {
    render() {
        return (
            <table>
                <tr><th>...</th></tr>
                <tr><th>...</th></tr>
            </table>
        );
    }
}

Lists

You may render() a list of elements to some compound types, like lists.
Each item requires a unique key so react can keep track of CRUD operations with list items.

class ListItems extends React.Component {
    render() {
        var items = [
          {key: "a", text: "aaa"},
          {key: "b", text: "bbb"},
          {key: "c", text: "ccc"},
        ]
        return items.map((x) =>
          <li key={x.key}> // key={foo} lets react update changes
            {x.text}
          </li>
        );
    }
}

class MyList extends React.Component {
    render() {
        return (
            <ul>
            <ListItems />
            </ul>
    }
}

Fragments

Fragments are a special wrapper type that allows you to return multiple top-level html-elements in one clump.
They do not need to be a homogenous collection of top-level elements.

You can use either of the following tags:

  • <React.Fragment>...</React.Fragment>
  • <>...</>
<table>
  <tr>
    <Columns />  // <-- fragment with several items
  </tr>
</table>
import React from 'react';

function Columns(props) {
    return (
        <React.Fragment>
          <td>foo</td>
          <td>bar</td>
          <td>baz</td>
        </React.Fragment>
    );
}

Null (force no render)

If a component's render() returns null,
then it won't render anything, even if it is included in a page.

The official-docs use a debug-info as an example (you'd only want to render if in development environment).

class DebugInfo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {debugEnabled: true};
    }

    render() {
        this.debugEnabled
          ? <p>debug info...</p>
          : null;
    }
}

Lifecycle Methods

NOTE:

An alternative to lifecycle methods is react hooks.

React components have methods to mount/unmount behaviours when the object is first created or destroyed.
These can set/unset timers to auto-update the object.
These behave similarly to constructor/destructor as hooks, except their events correspond with adding/removing them from the DOM.

Check out the tutorial (might need to scroll to methods).

class Foo extends React.Component {
  componentDidMount() { ... }      // runs after first 'render()'
  componentWillUnmount() { ... }   // runs if object is removed from the DOM
}