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