Table of contents
importReact,{FunctionComponent}from"react";constHello: FunctionComponent=()=>{return<div>Hallo</div>;};exportdefaultHello;importReact,{FunctionComponent}from"react";// Children's type is inferred by the FunctionComponent interfaceconstHello: FunctionComponent=({ children })=>{return<div>{children}</div>;};exportdefaultHello;<Hello><span>This span will be displayed, where children is used in the 'Hello' component</span><Hello>importReact,{FunctionComponent}from"react";// Type definitions for our prop bindingsinterfaceHelloProps{name: string;}// Functions can infer interfaces in typescript// We are passing props as an object with the `{}` syntax// Inside are all properties defined by our HelloProps interfaceconstHello: FunctionComponent<HelloProps>=({ name })=>{return<div>Hello, {name}</div>;};exportdefaultHello;interfaceExampleProps{requiredProp: number;optionalProp?: string;optionalPropWithDefault?: string;}constExample: FunctionComponent<ExampleProps>=({
requiredProp,
optionalProp,
optionalPropWithDefault ="Default value"})=>{return(<ul><li>{requiredProp}</li>{optionalProp&&<li>{optionalProp}</li>}<li>{optionalPropWithDefault}</li></ul>);};While react does not have a templating engine itself, common templating tasks can be easily achieved by using tsx.
constHello: FunctionComponent=()=>{constcondition=1>2;return(<div><div>I'm always shown</div>{condition&&<div>Only shown if condition is true</div>}</div>);};constHello: FunctionComponent=()=>{constcondition=1>2;return(<div><div>I'm always shown</div>{condition ? <div>Condition is true</div> : <div>Condition is false</div>}</div>);};constHello: FunctionComponent=()=>{letoutput=null;if(1>2){output=<div>Condition is true</div>;}else{output=<div>Condition is false</div>;}return(<div><div>I'm always shown</div>{output}</div>);};return(<div><div>I'm always shown</div>{/* We can use a function to put the condition inside the "template" */}{(()=>{if(1>2){return<div>Condition is true</div>;}else{return<div>Condition is false</div>;}})()}</div>);};First it's important to understand that react simply renders arrays as individual elements.
<ul>{[<li>One</li>, <li>Two</li>, <li>Three</li>]}</ul> will be rendered as:
- One
- Two
- Three
We can make use of that by using the map function to transform our data into markup, as map always returns an array.
constHello: FunctionComponent=({})=>{consttodos=["Todo 1","Todo 2","Todo 3"];return(<ul>{todos.map(todo=><li>{todo}</li>)}</ul>);};constHello: FunctionComponent=({})=>{consttodos=[{task: "Todo 1",done: false},{task: "Todo 2",done: true}];return(<ul>{todos.map(todo=>{if(todo.done){return<liclassName="todo done">[DONE] {todo.task}</li>;}else{return<liclassName="todo">{todo.task}</li>;}})}</ul>);};We are using react hooks for everything that's state / lifecycle related. Because hooks only work with functional components, we are solely using FunctionComponent instead of React.Component or classes.
constCounter: FunctionComponent=({})=>{const[counter,setCounter]=useState(0);return(<div>{counter}<buttononClick={()=>setCounter(counter=>counter+1)}>}>+</button></div>);};Functional components and hooks don't have a concept of lifecycles but we can get something similar using the useEffect hook, which runs every time the component is re-rendered.
// Without dependency arrayuseEffect(()=>{console.log("Component will rerender");});// With empty dependency arrayuseEffect(()=>{console.log("Component will mount");},[]);// With dependency arrayuseEffect(()=>{console.log("Watching property 'counter'");},[counter]);// With dependency arrayuseLayoutEffect(()=>{console.log("Component did render");});// With dependency arrayuseLayoutEffect(()=>{console.log("Componentn did mount");},[]);interfaceCommand<StateType>{execute(state: StateType): StateType;}typeMyState={counter: number;message: string;};classIncreaseCounterCommandimplementsCommand<MyState>{execute(currentState: MyState){// Always create a new object, never change existing statereturn{
...currentState,counter: currentState.counter++};}}classChangeMessageCommandimplementsCommand<MyState>{constructor(privatemsg: string){}execute(currentState: MyState){return{
...currentState,message: this.msg};}}constmyStateReducer=(state: MyState,command: Command<MyState>)=>command.execute(state);constinitialState: MyState={counter: 0,message: "Hello"};constTest: FunctionComponent=()=>{const[state,dispatch]=useReducer(myStateReducer,initialState);return(<div>
Counter: {state.counter}
Message: {state.message}<buttononClick={()=>dispatch(newIncreaseCounterCommand())}>Increase Counter</button><buttononClick={()=>dispatch(newChangeMessageCommand("👋"))}>Change Message</button></div>);};{
"Create a FunctionComponent": {
"prefix": "rfc",
"body": [
"import React, { FunctionComponent } from \"react\";",
"",
"interface $1Props {}",
"",
"const $1: FunctionComponent<$1Props> = ({}) => {",
"\treturn null;",
"}",
"export default $1;"
],
"description": "Creates a functional React component with the corresponding interface and exports."
}
}{
"Create a Jest Unit Test": {
"prefix": "jut",
"body": [
"import React from \"react\";",
"import { shallow } from \"enzyme\";",
"import $1 from \"./$1\";",
"",
"describe(\"$1\", ()=> {",
" it(\"should render to snapshot\", () => {",
" const component = shallow(<$1 />);",
" expect(component).toMatchSnapshot();",
" });",
"});"
]
}
}