type MessageBlockProps = { message: string };
class MessageBlock extends PureComponent<MessageBlockProps> {}
class MessageBlock extends PureComponent<MessageBlockProps> { render(){} }
class MessageBlock extends PureComponent<MessageBlockProps> { render() { const { message } = this.props; return <div className="ma-message">{message}</div>; } }
type MessageBlockProps = { message: string };
const MessageBlock: FC<MessageBlockProps> = ({ message }) => ();
const MessageBlock: FC<MessageBlockProps> = ({ message }) => ( <div className="ma-message">{message}</div> );
type BtnProps = {};
class BtnWithCounter extends PureComponent<BtnProps> {}
class BtnWithCounter extends PureComponent<BtnProps> { state = { counter: 0 }; }
handleClick = () => { const { counter: oldValue } = this.state; const counter = oldValue + 1; this.setState({ counter }); this.props.onAfterChange(counter); };
render() { const { counter } = this.state; return ( <button type="button" onClick={this.handleClick}> Clicked {counter} times </button> ); }
type BtnProps = { onAfterChange: (v: number) => void; };
const BtnWithCounter: FC<BtnProps> = ({ onAfterChange }) => { return <></> }
const [counter, setCounter] = useState(0); // setup state const BtnWithCounter: FC<BtnProps> = ({ onAfterChange }) => { return <></> }
const handleClick = () => { // define handler const newValue = counter + 1; // implement logic setCounter(newValue); // update state onAfterChange(newValue); // invoke callback };
return ( <button type="button" onClick={handleClick}> Clicked {counter} times </button> );
const users = ['Maria', 'Andriy', 'Ihor']; const UserList = () => ( <ul> {users.map((user) => ( <li key={user}>{user}</li> ))} </ul> );
import img from './my-image.png'; const Avatar = () => <img src={img} alt="MyPhoto" />;
In ideal world - the are should be a single reason to change the component
Component should be open for extension, but closed for modification