React

Workshop

Setup

Workshop Projekt

git clone ssh://git@git.konform.com:7999/~jh/react-workshop.git

cd react-workshop

yarn install

# tilføj react-workshop.test til din /etc/hosts fil, hvis ikke du bruger dnsmasq

yarn start

# åbn http://react-workshop.test:3000/

# åbn i din editor

DevTools

Opgave 1

Basic Component

import React, { Component } from 'react';
import PropTypes from 'prop-types';

export default class ComponentName extends Component {
    static propTypes = {
        dispatch: PropTypes.func.isRequired,
    };

    static defaultProps = {};

    constructor(props) {
	super(props);
	this.state = {
            show: true,
        };
    }

    render() {
        return (
            <div>
                {this.state.show && (
                    <div className="thing">thing</div>
                )}
            </div>
        );
    }
}
import React from 'react';
import PropTypes from 'prop-types';

const ComponentName = (props) => (
    <div>
        {props.show && (
            <div className="thing">thing</div>
        )}
    </div>
);

ComponentName.propTypes = {
    show: PropTypes.bool
};

ComponentName.defaultProps = {
    show: true,
};

export default ComponentName;
import Box from '../../components/box';
import Sidebar from '../../components/sidebar';

const SIDEBAR_CONTENT = '../../constants/sidebarcontent';

const Main = () => (
    <div className="container">
        <Sidebar content={SIDEBAR_CONTENT} />

        <div className="container__content">
            <Box>Baz</Box>
        </div>
    </div>
);

export default Main;

JSX

# loop

<ol>
    {this.props.users.map((user) => (
        <li>{user.name}</li>
    ))}
</ol>
# javascript

<div>
    {this.getUsers()}
</div>
# conditional content

<div>
    {!!this.state.users.length && (
        <ol>
            {this.props.users.map((user) => (
                <li>{user.name}</li>
            ))}
        </ol>
    )}
</div>

# eller

<div>
    {this.state.users.length ? (
        <ol>
            {this.props.users.map((user) => (
                <li>{user.name}</li>
            ))}
        </ol>
    ) : <div>Ingen brugere fundet</div>}
</div>

HTML: "kebab-case"

JSX: "camelCase"

 

Fordi "class" er et reserved word i JS, hedder attributten className.

(Ligesom i DOM)

Attributes

# attributes

<input 
   type="text" 
   name={this.props.name}
   name={this.props.placeholder}
   tabIndex={this.props.tabIndex ? this.props.tabIndex : '-1'}
/>
# events

<button onClick={this.updateUserList}>
    Update users
</button>
class Thing extends Component {
    render() {
        return (
            <button onClick={this.updateUserList.bind(this)}>
                Update users
            </button>
        );
    }
}
class Thing extends Component {
    render() {
        return (
            <button onClick={this.updateUserList}>
                Update users
            </button>
        );
    }

    
    updateUserList = () => {
        // ...
    }
}

Lifecycle methods

  • mounting
  • updating
  • unmounting
  • errors

Mounting

constructor(props) {
  super(props);
  this.state = {
    color: props.initialColor
  };
}

componentWillMount() {}

render() {}

componentDidMount() {}

Updating

componentWillReceiveProps(nextProps) {
    // componenten har fået nye props (nextProps)
    // de gamle props kan stadig tilgås via this.props
    // hvis man har state der skal ændres baseret på props
    // så kan det gøres nu

    // kald til setState skipper denne
    // nextProps kan godt være det samme som this.props
}

shouldComponentUpdate(nextProps, nextState) {
    // "should" indikerer at den forventer en boolean return
    // anvendes til at optimere sine renders, 
    // ved false skipper man render
}

componentWillUpdate(nextProps, nextState) {
    // shouldComponentUpdate returnerede true så komponenten skal opdateres
    // setState kan IKKE kaldes her
}

render() {}

componentDidUpdate(prevProps, prevState) {
    // componenten blev re-rendered
    // et godt sted
}

Unmounting

componentWillUnmount() {
    // componenten er ved blive fjernet fra DOM'en
    // bruges hvis der er brugerinput eller lignenede leftover
    // så er dette en chance for fx at gemme inden indholdet slettes
}

Errors

componentDidCatch(error, info) {}

Opgave 2 + 3

Redux

this.props.dispatch({
    type: 'ACTION_USERS_FETCHED',
    data: {
        users: [...],
    },
});
import { ACTION_ADD, ACTION_REMOVE } from '../constants/actions/demo';

const defaultState = {
    count: 0,
};

function modifyByAmount(state, amount) {
    return {
        ...state,
        count: state.count + amount,
    };
}

function increase(state) {
    return modifyByAmount(state, 1);
}

function decrease(state) {
    return modifyByAmount(state, -1);
}

export default function demoReducer(state = defaultState, action) {
    switch (action.type) {
        case ACTION_ADD:
            return increase(state);
        case ACTION_REMOVE:
            return decrease(state);
        default:
            return state;
    }
}
import { connect } from 'react-redux';

@connect((state) => ({
    dispatch: state.dispatch,
    dataFromStore: state.example.data,
}))
export default class Example extends Component {

}

Opgave 4+

DONE

 

Så er der VR!

Workshop

By Jakob Hyldtoft

Workshop

  • 532