React
Vue

Appending to DOM

ReactDOM.render(JSX or <component/>, elementToMountOn)
 

binding methods

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "Hello"
    };
    // Change code below this line
    this.handleClick = this.handleClick.bind(this)
    // Change code above this line
  }
  handleClick() {
    this.setState({
      text: "You clicked!"
    });
  }
  render() {
    return (
      <div>
        { /* Change code below this line */ }
        <button onClick={this.handleClick}>Click Me</button>
        { /* Change code above this line */ }
        <h1>{this.state.text}</h1>
      </div>
    );
  }
};
 

child interact parent

  • pass methods to child just like prop
  • callback is passed
class MyApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      inputValue: ''
    }
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(event) {
    this.setState({
      inputValue: event.target.value
    });
  }
  render() {
    return (
       <div>
        { /* Change code below this line */ }
        <GetInput input={this.state.inputValue} handleChange={this.handleChange}/>
        <RenderInput input={this.state.inputValue}/>
        { /* Change code above this line */ }
       </div>
    );
  }
};

class GetInput extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <h3>Get Input:</h3>
        <input
          value={this.props.input}
          onChange={this.props.handleChange}/>
      </div>
    );
  }
};
 

Component

  • core of react
  • everything in react is component
  • 2 ways to create
    1. Javascipt Function
    2. ES6 classes

Using JS function

  • creates stateless functional component
  1. js function that returns JSX or null
  2. function name should begin with capital letter
const DemoComponent = function(){
    return (
        <div className="customClass"/>
    )
}

Using Class syntax

  1. extend React.component
  2. make a constructor
  3. make a render method
class Kitten extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return (
            <h1>Hi!</h1>
        )
    }
}
  • Kitten extends React.Component class, so now it has many features of react.
    • local state, lifecycle hooks
  • stateless functional component
    • function that accepts props, returns JSX
  • stateless component
    • class that extends React.component, but does not uses an internal state
  • stateful component
    • class component that maintains own internal state, referred simply as react components
    • common pattern: reduce stateful components & create stateless components
      • helps contain state management to specific area of app
      • improves dev & maintenance as it makes easier to follow changes to state
 

how to compose complex component using multiple components

  • You can render JSX elements, stateless functional components, and ES6 class components within other components.
const Fruits = () =>{
    return (
        <div>
            Fruits
        </div>
    )
}
const Vegetables = () =>{
    return (
        <div>
        Vegetables
        </div>
    )
}
class Foods extends React.Component{
    constructor(props){
        super(props)
    }
    render(){
        return (
            <div>
                <Fruits/>
                <Vegetables/>
            </div>
        )
    }
}
 
 

Hooks Lifecycle

Mounting:

  1. useState() -> lazy initializers
  2. render: rest of the function code
  3. update DOM
  4. run layout effects
  5. Browser paints screen
  6. run effects

Updating:

  1. render: rest of the function code
  2. update DOM
  3. cleanup layout effects
  4. run layout effects
  5. Browser paints screen
  6. clean up side effects of prev render
  7. run effects

Unmount:

  1. cleanup layout effects
  2. clean up side effects of prev render
 
<div v-if="charged">You were charged</div>

jsx

  • benefit: full programmatic power of js in html
  • not valid js, hence must be converted to js. done using babel transpiler
  • simply include js code within round brace
  • must return a single element
  • tool to write readable html within JS
const JSX = (
    <div>
        {/* some comment here */}
        <h1 className="hello">Hello</h1>
    </div>
)
//Render JSX
ReactDOM.render(JSX, document.getElementById('challenge-node'))
  • class is reserved keyword in JS, therefore JSX uses className to define class in html
    • naming convention for all HTML attributes and event references in JSX become camelCase. For example, a click event in JSX is onClick, instead of onclick
  • has concept of self-closing tag for all elements
    • ex: <div/> = <div></div>
    • this is useful in adding react component

jsx

  • uses templates instead
  • supported via babel plugin
  • Life Cycle
    • componentDidUpdate - going to be depreceated in 17
    • componentDidMount
      • call API
      • attach event listener
    • componentWillUnmount
    • shouldComponentUpdate(nextProps, nextState)
 

using props

const List = () = {
    return (
        <p>{props.tasks.join(', ')}</p>
    )
}

<List tasks={["learn react","learn state"]}>
  • giving default value
        ShoppingCart.defaultProps = {
            items:0
        }
    
  • giving propTypes
        ShoppingCart.propTypes = {
            items: PropTypes.func.isRequired
        }
        // items should be of type function
        // items is a required property
    
    • there are many types available apart from primitive types
    • function -> func, boolean -> bool
    • PropTypes is imported independently from React, like this: import PropTypes from 'prop-types';
    • same way for class & functional component
  • in Class component, it is accessed using this.props.data
  • allows unidirectional data flow
 

Redux

  • Predictable state container for JS apps
  • can be used with any UI library

Async

Redux Thunk middleware

Basic

  1. create redux store

    const reducer = (state = 5) => state
    const store = Redux.createStore(reducer)
    
  2. get current state from store

    store.getState()
    
  3. Define Action, change state -> done by dispatching action

    • action: simple js obj, containing info about event that has just occured
    • sometimes carries data
    • must have type property
    const action = {
      type: 'LOGIN',
    }
    
  4. Define action creator

    • simple js function that returns an action
    const actionCreator = () => {
      return action
    }
    
  5. Dispatch action to store

    store.dispatch(action)
    store.dispatch(actionCreator)
    
  6. reducer

    • how to respond to an action
    • (state, action) => state
    • no side effect, no api call
    const authReducer = (state = defaultState, action) => {
      switch (action.type) {
        case 'LOGIN':
          return {
            authenticated: true,
          }
        default:
          return state
      }
    }
    
  7. subscribe - called when action are dispatched against store

    store.subscribe(function () {
      count += 1
    })
    
  8. composing reducers

    • instead of having multiple state, have multiple reducers
    • combineReducers
      • simple object
      • key are name for associated piece of state
      • write reducer for each piece of application state
    const rootReducer = Redux.combineReducers({
      auth: authReducer,
      count: counterReducer,
    })
    const store = Redux.createStore(rootReducer)
    
  9. handle async operation

    • Redux Thunk middleware
    const handleAsync = () => {
      return function (dispatch) {
        // Dispatch request action here
        dispatch(requestingData())
        setTimeout(function () {
          let data = {
            users: ['Jeff', 'William', 'Alice'],
          }
          // Dispatch received data action here
          dispatch(receivedData(data))
        }, 2500)
      }
    }
    const store = Redux.createStore(
      asyncDataReducer,
      Redux.applyMiddleware(ReduxThunk.default)
    )
    
    • declare async action
    • takes dispatch as arg
    • call after operation finishes
 

ref, createRef, useRef

useRef() is basically useState(React.createRef())[0]

 

useState

const [value, setValue] = useState(initialValue)

Things to keep in mind:

  • if initialValue is a computation, make it function, ie instead of this

    const [] = useState(localStorage.getItem('name') || '')
    

    do this

    const [] = useState(() => localStorage.getItem('name') || '')
    
    • useState ignores the initialValue after first render
    • also called Lazy state initialization

Use old value

useEffect(() => {
  setCount((oldValue) => (oldValue += 1))
})

State

  • data(){ return {

    } }

  • encapsulated within component

useCallback

  • used when memoization is involved
  • memoization
    • caching is a form of memoization
    • referential equality
 

useEffect

  • synchronize state of the world with state of my app
useEffect(callback, dependencyArray)
  • custom hook: a function that uses hooks

  • to give hint to eslint system, custom hook should start with use, just a convention to tell ecosystem that it is custom hook

    function useLocalState(key, defaultValue) {
      const [state, setState] = useState(() => {
        return localStorage.getItem(key) || defaultValue
      })
      useEffect(() => {
        localStorage.setItem(key, state)
      }, [key, state])
      return [state, setState]
    }
    
  • as a good practice, always serialize/deserialize data before reading/writing to localStorage

    const [state, setState] = useState(() => {
      const value = localStorage.getItem(key)
      if (value) {
        return JSON.parse(value)
      }
      return defaultValue
    })
    
    useEffect(() => {
      localStorage.setItem(key, JSON.stringify(state))
    }, [key, state])
    
 

useReducer

  • sometimes you want to separate the state logic from the components that make the state changes.

  • if you have multiple elements of state that typically change together, then having an object that contains those elements of state can be quite helpful.

  • as useState

const countReducer = (state, newState) => newState

function Counter({ initialCount = 0, step = 1 }) {
  const [count, setCount] = React.useReducer(countReducer, initialCount)
  const increment = () => setCount(count + step)
  return <button onClick={increment}>{count}</button>
}
  • compute inside reducer function
const countReducer = (count, change) => count + change

function Counter({ initialCount = 0, step = 1 }) {
  const [count, changeCount] = React.useReducer(countReducer, initialCount)
  const increment = () => changeCount(step)
  return <button onClick={increment}>{count}</button>
}
  • as callback
const countReducer = (state, action) => ({
  ...state,
  ...(typeof action === 'function' ? action(state) : action),
})

function Counter({ initialCount = 0, step = 1 }) {
  const [state, setState] = React.useReducer(countReducer, {
    count: initialCount,
  })
  const { count } = state
  const increment = () =>
    setState((currentState) => ({ count: currentState.count + step }))
  return <button onClick={increment}>{count}</button>
}
  • as dispatch object
function countReducer(state, action) {
  const { type, step } = action
  switch (type) {
    case 'increment': {
      return {
        ...state,
        count: state.count + step,
      }
    }
    default: {
      throw new Error(`Unsupported action type: ${type}`)
    }
  }
}

function Counter({ initialCount = 0, step = 1 }) {
  const [state, dispatch] = React.useReducer(countReducer, {
    count: initialCount,
  })
  const { count } = state
  const increment = () => dispatch({ type: 'increment', step })
  return <button onClick={increment}>{count}</button>
}