JSX
- a syntax extension to JavaScript produces React “elements”.
- React doesn’t require use JSX.
- React DOM escapes any values embedded in JSX to string before rendering them. This helps prevent XSS (cross-site-scripting) attacks.
- Babel is recommended use for the editor
JSX Convention
- inside a scope, it requires Capital Name and can use dot notation, but not expression MyComp[“checkbox01”]. eg:
- literal string. ex:
color=”red” || color={‘red’}
msg=”<hello” || msg={’<hello’} - prop default to true. eg:
<MyComponent a />
(this.props.a => true) - render return:
+ React DOM
+ Arrays React DOM
+ ReactDOM portals (aim to render element in a different position)
+ value of number, string, boolean
+ ex: render() {return [<li>a</li>, <li>b</li>]} - children could be any sort of data:
+ data (string/number/json/etc)
+ ReactDom
+ Functional Component
+ etc - Boolean, Null, and Undefined Are IGNORED in Render => not thing
- Short return for condition
{showHeader && <Header />}
Rendering elements:
- React elements are plain objects and are cheap to create.
- React DOM takes care of updating the DOM to match the React elements.
- React Only Updates What’s Necessary: React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.
- We could have one or many “root DOM”, and everything inside “root DOM” will be managed by React DOM.
- To render a React element into a root DOM node, pass both to
ReactDOM.render
Components and Props
- Components help split the UI into the independent part and make it reusable. Currently, ReactJS has two types of component
1. Functional Component: just a JS function that receives a single “props” and returns React elements.
eg: function Welcome(props) {return <h1>{props.greeting}</h1>}
2. Class Component (ES6): a class extends from React.Component
- All React components must act like pure functions with respect to their props. A component cannot update its own props unless they are arrays or objects.
- The
React.lazy
(return a Promise/async) function lets you render a dynamic import as a regular component. Usually go with Suspense Component.<Suspense fallback={<div>Loading...</div>}>...</>
+ Not supported in some server rendering so, use loadble-component instead.
+ Only support export default.
- “<Fragment>” component of React allows returning multiple elements. Short syntax: <>…</>. Fragment also need a "key" when inside “loop/map”
eg: return (<> <td>CHILD A</td><td>CHILD B</td> </>) - label “for” attribute in HTML is represented by “htmlFor”
- props "key" (see list and key)
- props "children": represent for the arbitrary content of the component.
ref
- Only use when it’s really needed
- need input a function ref={(el) => {…}} OR implemented by React.createRef()
- only pass to children Component by React.forwardRef(props, ref)
ref
updates happen beforecomponentDidMount
orcomponentDidUpdate
# option 1: declare a variable equal to React.createRef()
this.textInput = React.createRef();<input
type="text"
ref={this.textInput} />this.textInput.current.focus()#option 2: input a function
setTextInputRef(el) {
this.textInput = el
}<input
type="text"
ref={this.setTextInputRef} /><input
type="text"
ref={ el => this.textInput = el } />
Forwarding refs (React.forwardRef)
- forward ref to children-component by using forwardRef.
- the function input 2 parameters props and ref and output a ReactDom
# Function Component
const SampleButton = React.forwardRef((props, ref) => (
<button ref={ref} className="button">
{props.children}
</button>
));
const ref = React.createRef();
<SampleButton ref={ref}>Click me!</SampleButton>;
- For class Component
# Class Component
const Counter = React.forwardRef((props, ref) => {
class Counter extends React.Component {
constructor(props) {
super(props)
this.state = {
count: 0
}
} render() {
return (
<div>
Count: {this.state.count}
<button ref={ref} onClick={() => this.setState({count: this.state.count + 1})}>Incr</button>
</div>
)
}
}
return <Counter />
})
State and Life Cycle
- State is called local or encapsulated.
- it’s very important to free up resources taken by the components when they are destroyed. Hence, remove all event in componentWillUnMount()
- Life circle:
1. ReactDOM.render()
2. constructor(props)
3. render() => insert into the DOM
4. componentDidMount()
. setState() => render()
.componentWillUnmount() when the component removed from the DOM - React may batch multiple
setState()
calls into a single update for performance. setState
would change state and may lead to re-render the component. This is an expensive operation, it would cause a performance issue if it is not an async process.- Because
this.props
andthis.state
update asynchronously, we should not rely on their values to calculate the next state. We can update with the second formsetState
(input a function).
HANDLING EVENT
- Use “e.preventDefault()” to prevent default instead of "return false".
- To prevent the event bind “this” to your function, you could:
1. define the function with an arrow function
2. binding “this” of class to that function.
// option 1.1:
handleClick = () => {
console.log('this is:', this);
}// options 1.2:
<button onClick={() => this.handleClick()}>// options 2.1:
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>// options 2.2:
constructor() {
...
this.handleClick = this.handleClick.bind(this)
}<button onClick={this.handleClick}>Delete Row</button>
Conditional Rendering
List and Key
- Keys help React identify which items have changed, are added, or are removed.
- In React, when creating a list of React Elements, you have to give every element a “key”. It should be unique, static, and must set on the represented element.
- Diffing algorithm of React checks mapping key and state change to decide which DOM element would be changed. If
key
value is not unique and static, it would lead to some wrong updates from React. Never use the random key, it would cause really bad performance because re-rendering all elements every time. - We can skip the
key
only when the list and items are static (they are not computed and do not change) and the list is never reordered or filtered. key
is a special attribute of React, it does not allow access.
const listItems = items.map((item, index) =>
<ListItem item={item} key={item.id} />
);
- We could use curly braces inside the “map”
FORM
- specify “value” (!= null, undefined) in the “controlled component”, it only could change through React.
<textarea>, <select>
uses avalue
attribute to show/selected instead of its content.- For multiple <select> add attributes “multiple=true”.
eg:<select multiple={true} value={['B', 'C']}>
<input type="file">
its value is read-only, it is an uncontrolled element.- Tip: we could write a general reusable handleChangeEvent method for all elements.
Context:
- allow passing a value to its children-component implicitly.
- A component only can apply one context.
- If it’s not specified the contextName inside a Component
static contextType = ThemeContext;
,
OR
MyComponent.contextType = ThemeContext
it would apply the context of the closest [Context].Provider . - Get the value inside the Component by “this.context”
- Apply it sparingly because it makes component reuse more difficult. Use passing the Component as props to easily call it.
ex: const ThemeContext = React.createContext(‘light’);
<ThemeContext.Provider value=”dark”>…</>
Context.Consumer
- This lets you subscribe change to a context
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
lifting state up
- Move the state of children to the nearest suitable ancestor.
- The ancestor would own the shared states is called “source of truth”.
- The event-change-function is defined at parent component then pass it to children
ROUTER
Class Default Props
Integrating with other Library
- usually along with ref
https://reactjs.org/docs/integrating-with-other-libraries.html
TOOL SUPPORT
# CLI tools
Create React App (client side rendering)
Next.js (server side rendering + client side rendering - multi page)
Gatsby# bundled tools Webpack, Rollup or Browserify: parse code JSX to JS, ES6 to ES5 then compress to mini files# analysis code: eslint-plugin-jsx-a11y
{
"extends": ["react-app", "plugin:jsx-a11y/recommended"],
"plugins": ["jsx-a11y"]
}# test accessible HTML aXe, aXe-core and react-axe
References
Webpack code-splitting support:
- prevent duplicated modules.
- import dynamic lib module.
Uncontrolled Components (when we want the Dom El control value itself)
Formik (the easier form way for React)
https://robinpokorny.medium.com/index-as-a-key-is-an-anti-pattern-e0349aece318