react-components Tailwind Templates

React Components

Learning reactive approach for building components. Used packages: tailwind-css, classnames, react-icons (prop-types)

BUTTONS

Prop approach

<Button text="click here"

Children approach

<Button>Click here!</Button>
This work fine with everything:

  • plain text
  • jsx components e.g. <Icon/>
  • html elements
    etc.

<Button primary>Clik me!</Button> === <Button primary={true}>Clik me!</Button>

<Button>Clik me!</Button> ~~= <Button primary={false}>Clik me!</Button>
It's actually undefined, but treated the same as false

STYLING:

Introducing CSS Box Model

https://www.w3schools.com/css/css_boxmodel.asp

Classnames library:

https://www.npmjs.com/package/classnames

import className from "classnames";
// import classnames from "classnames";  // as in documentation, both imports are correct

const finalClassName = className("py-1.5", "border", "border-sky-600"); // "py-1.5 border border-sky-600"

const finalClassName = className({
  "py-1.5": true, // object keys cannot have dashes and special signs within it, unless is is wrapped as string (" or ')
  border: false,
  "border-sky-600": 10, //any truthy value
  "bg-sky-600": "",
}); // "py-1.5 border-sky-600"

const finalClassName = className("py-1.5", {
  // always
  border: resp_1, // the rest is conditional
  "border-sky-600": resp_2,
  "bg-sky-600": resp_1,
}); // "py-1.5 ...?"

const finalClassName = className("py-1.5", "border", "border-sky-600");
const finalClassName = className("py-1.5", "border", "border-sky-600");
console.log(finalClassName);

Tailwind and Tailwind-merge

https://tailwindcss.com/docs/ https://www.npmjs.com/package/tailwind-merge

Reusable "Presentation Components"

  1. Create a new component that shows a handful of JSX elements
  2. Make sure component accepts and uses {children} prop
  3. Allow extra classNames to be passed in and merge them - with className lib
  4. Take extra prop, pass them trough to root element - with {...rest} prop

check implementation here

React-icons

https://react-icons.github.io/react-icons/

npm install --save-exact [email protected]


Design proccess

What state and event handlers are there?

  1. List out what a user will do and changes they will see while using the app
  2. Categorize each step as state or event handler
  3. Group common steps. Remove duplicaes. Rewrite descriptions.

What name and type?

  1. Look at mockup (draft). Remove or simplify parts that aren't changing
  2. Replace remaning element with text descriptions
  3. Repeate #4 and #5 with a different variation
  4. Imagine you have to write a function that returns the text of steps #5 and #6. In addition to your component props - what other arguments would you need?

Where it is defined?

  1. Decide where each event handler and state will be defined

Example (Accordian.js):

# What?

  1. How accordion works: user clicks on section -> it should force the previously opened section to collapse and itself to expand. Actually this could be repeated for each section.

  2. State - something changes on the screen (collapses, expands). Event handler - user perform some action (clicks).

  3. State - sections are collapsing and the one clicked is expanding (1). Event handler - clicking on section header (1).

# Name and type

!! Avoid arrays / objects to be a type of piece of state !!
number, boolean, string should be fine

  1. Text of headers does not change, text of 'body' also not change at all

  2. Expanded - is a name of expanded section (1). Collapsed - name of sections that are collapsed (2+) [exp. coll. coll.]

  3. [coll. exp. coll.], [coll. coll. exp.],

  4. Imagine function, props and their types

function myFunction(items, /*???*/) {...}
myFunction(propsItems, /*???*/);  // ['expanded', 'collapsed', 'collapsed']
myFunction(propsItems, /*???*/);  // ['collapsed', 'expanded', 'collapsed']
myFunction(propsItems, /*???*/);  // ['collapsed', 'collapsed', 'expanded']

/???/ - might be expendedIndex = 0, 1, 2; so the integer

# Where?

  • does any other component has reasonable need to know the peace of state value? --> YES -> App.js | NO -> component.js
  • event handler ususally is defined in the same component where the state it modifies (but might be used in another)

React does not print booleans, nulls, undefined

JS Boolean Expressions

|| returns the firts truthy value && returns the first falsey value or the last truthy

React useState delays:

PROBLEM: React updates the piece of state but not immidatiely...

Batching is an optimization of React causing above issue but allowing to update few states in the same moment - the application works fast and smooth

How to see the issue? Go to console:

$0.click(); // opens or closes the content
$0.click();
$0.click(); // the accordion does not come back to the initial state

It is only a problem when clicks become very quick one after another. Normal human user wouldn't be able to do this.

SOLUTION 1: Force React to update instantly

Truning batching off, but slowing app down...

SOLUTION 2: Access the most up to date value with Functional State Update

const [value, setValue] = useState(-1)
...
const handleClick = (newIdx) => {
    setValue((current) => {
    // use 'current' in the logic instead of 'value'
    })
}

more in components/Accordion.js or Dropdown.js

Event handler in mapping function

const handleWithEvent = (event) => {...}
const handleWithProps = (passedOption) => {...}

consr rendered = data.map((option) => {
    return <div> onClick={handleWithEvent} </div>
    return <div> onClick={() => handleWithProps(option)} </div>
})

MASTERING DESIGN PROCESS - Dropdown:

  1. & 2. Steps & Categorize Clicks on dropdown - event List of options appears - state Clicks on option - event List of options disappear - state Clicked item appears shows in the box - state

  2. Rewrite: Events: clicks on dropdown, clicks on option (2) States: dropdown expanded or collapsed, selected option in the box (2)

  3. Look at mockup. Remove or simplify parts that aren't changing

  4. Replace remaning element with text descriptions Menu closed, no option selected Menu opened, no option selected Menu closed, 1st option is selected

  5. Nothing to do with this simple component

  6. Funtion + other arguments needed STATES - name and type (and possible values):

// menu open or closed
myFunction(opts: list, isOpen: boolean) // true => menu opened, false => menu closed
// selected one of the option or null
myFunction(opts: list, selested: null | opts[n]) // nothing selected, {label: x, value, x1}

EVENTS - names for handlers: handleSelect, handleToggle

  1. Where?

    optionSelected + handleSelect -> parent menu opnened/closed + handleToggle -> Dropdown.js

Handling Input aka "Controlled Input"

  1. Create a new piece of state
  2. Create event handler watching on onChange event
  3. When onChange event fires, get the data from the input
  4. Update the state with that data
  5. Pass state to the input as the value prop

EXAMPLE + How react renders the above:

Look at:

This will be repeated in Dropdown component - chech

.

ad. 1. Create a new piece of state

in parent component (SearchBar) and pass it to the child component (TextInput) as prop named "value".
Whenever data is passed to the "value prop" react forceably updates the text in text input

ad. 2. Create event handler

called "handleChange" in parent component
and pass it to child as onChange prop

ad 3. When onChange event fires, get the data from the input

when user pass anythign to the input, react fires the onChange and thus hadleChange function with new data

ad. 4. Update the state with that data

inside handleChange function,

ad. 5. Pass state to the input as the value prop

because the state was updated the parent (SearchBar) is going to rerender itself and pass new state to the value prop of child (TextInput) ...react foceably updates the text...

Comminity Convention with Prop Names

Refers only to child component, not the parent one - there the names (piece of state and event handler) could be whatever I choose

form control component - any kind of component where user provide some input value (text, text area, text input, dropdown, checkbox etc.)
value - name of the prop where the current value is stored
onChange - name of the prop called when value changed

Clicking on second dropdown (or anywhere else) should close the first dropdown - look here

JS Solution: Document-wide event listiner

const handleClick = (event) => {
  console.log(event.target);
};

document.addEventListener("click", handleClick);

Event capturing / bubbling

Whenever user interact with page (clik, drag, drop etc..) browser searches for event handlers corresponding to user action. This searching is divided into 3 phases: Capture Phase --> Target Phase --> Bubble Phase

Example application:

<body>
  <div>
    <button>Click me!</button>
  </div>
</body>

User clicks on button, so the browser starts searching the event handler.

Ad. Capture Phase

Browser looks at element cliked