Веб-приложение или сайт, который загружает только одну страницу и все последующие запросы обрабатываются без полной перезагрузки страницы.
Приложение, которое может работать как на стороне сервера, так и на стороне клиента.
import React from 'react';
function Form() {
return (
<div className="form">
<input placeholder="Ключ заметки" />
<textarea placeholder="Текст заметки" />
<button>Добавить новую заметку</button>
</div>
);
}
import React from 'react';
class Form extends React.Component {
render() {
return (
<div className="form">
<input placeholder="Ключ заметки" />
<textarea placeholder="Текст заметки" />
<button>Добавить новую заметку</button>
</div>
);
}
}
<div id="root"></div>
import React from 'react';
import ReactDOM from 'react-dom';
import Form from './Form';
ReactDOM.render(<Form />, document.getElementById('root'));
<div>
<img className="logo" src="./images/logo.svg" />
<h1 className="title">Список заметок</h1>
</div>
React.createElement(
"div",
null,
React.createElement("img", { className: "logo", src: "./images/logo.svg" }),
React.createElement("h1", { className: "title" }, "Список заметок")
);
<input class="name" tabindex="2" />
<input className="name" tabIndex="2" />
<div>
<span>Введите ваше имя:</span><br>
<input type="text">
</div>
<div>
<span>Введите ваше имя:</span><br />
<input type="text" />
</div>
|
|
|
|
function MyComponent() {
return (
<p>Первый абзац</p>
<p>Второй абзац</p>
);
}
function MyComponent() {
return (
<div>
<p>Первый абзац</p>
<p>Второй абзац</p>
</div>
);
}
function MyComponent() {
return (
<React.Fragment>
<p>Первый абзац</p>
<p>Второй абзац</p>
</React.Fragment>
);
}
const user = { name: 'Максим' };
function Greeting() {
return <div>Привет, {user.name}</div>;
}
const someHtml = '<strong>Максим</strong>';
function Greeting() {
return <div>Привет, {someHtml}</div>;
}
const someHtml = '<strong>Максим</strong>';
function Greeting() {
return (
<div dangerouslySetInnerHTML={{ __html: someHtml }} />
);
}
import Form from './Form';
import Notes from './Notes';
function NotesApp() {
return (
<div className="notes-app">
<Notes />
<Form />
</div>
);
}
function Notes() {
return (
<div className="notes">
<Note name="Books" text="Books to read" />
<Note name="Music" text="Music to listen" />
<Note name="Films" text="Films to watch" />
</div>
);
}
function Note({ name, text }) {
return (
<div className="note">
<h1>{name}</h1>
<p>{text}</p>
</div>
);
}
export default class Note extends React.Component {
render() {
const { name, text } = this.props;
return (
<div className="note">
<h1>{name}</h1>
<p>{text}</p>
</div>
);
}
}
import PropTypes from 'prop-types';
function Note({ name, text }) {
return ...
}
Note.propTypes = {
name: PropTypes.string,
text: PropTypes.string.isRequired
};
Note.defaultProps = {
name: 'Note name'
};
import PropTypes from 'prop-types';
export default class Note extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired,
text: PropTypes.string.isRequired
}
static defaultProps = { name: 'Note name' }
render() {
const { name, text } = this.props;
return ...
}
}
import React from 'react';
const ThemeContext = React.createContext('light');
export default ThemeContext;
import ThemeContext from './ThemeContext.js';
function Note() {
return (
<ThemeContext.Consumer>
{theme => {
return <div>...</div>;
}}
</ThemeContext.Consumer>
);
}
import ThemeContext from './ThemeContext.js';
function NotesApp() {
return (
<ThemeContext.Provider value="dark">
...
</ThemeContext.Provider>
);
}
function Notes() {
return (
<div className="notes">
<Note name="Books">
<span>Books to read</span>
<button>Like!</button>
</Note>
</div>
);
}
function Note({ name, children }) {
return (
<div className="note">
<h1>{name}</h1>
<p>{children}</p>
</div>
);
}
export default class Note extends React.Component {
state = { viewType: 'short' }
viewFull = () => this.setState({ viewType: 'full' })
render() {
const { viewType } = this.state;
return (
<div className="note">
<h1>Название заметки</h1>
{viewType === 'short'
? (
<React.Fragment>
<p>Краткое содержание</p>
<button onClick={this.viewFull}>Читать подробнее</button>
</React.Fragment>
) : <p>Полный текст</p>
}
</div>
);
}
}
export default class Note extends React.Component {
state = { viewType: 'short' }
viewFull = () => this.setState({ viewType: 'full' })
render() {
const { viewType } = this.state;
return (
<div className="note">
<h1>Название заметки</h1>
{viewType === 'short'
? (
<React.Fragment>
<p>Краткое содержание</p>
<button onClick={this.viewFull}>Читать подробнее</button>
</React.Fragment>
) : <p>Полный текст</p>
}
</div>
);
}
}
export default class Note extends React.Component {
state = { viewType: 'short' }
viewFull = () => this.setState({ viewType: 'full' })
render() {
const { viewType } = this.state;
return (
<div className="note">
<h1>Название заметки</h1>
{viewType === 'short'
? (
<React.Fragment>
<p>Краткое содержание</p>
<button onClick={this.viewFull}>Читать подробнее</button>
</React.Fragment>
) : <p>Полный текст</p>
}
</div>
);
}
}
export default class Note extends React.Component {
state = { viewType: 'short' }
viewFull = () => this.setState({ viewType: 'full' })
render() {
const { viewType } = this.state;
return (
<div className="note">
<h1>Название заметки</h1>
{viewType === 'short'
? (
<React.Fragment>
<p>Краткое содержание</p>
<button onClick={this.viewFull}>Читать подробнее</button>
</React.Fragment>
) : <p>Полный текст</p>
}
</div>
);
}
}
constructor
↓
(static) getDerivedStateFromProps
↓
render
↓
componentDidMount
(static) getDerivedStateFromProps
↓
shouldComponentUpdate
↓
render
↓
componentDidUpdate
shouldComponentUpdate
↓
render
↓
componentDidUpdate
componentWillUnmount
function NotesList({ notes }) {
return notes.map(note => (
<Note name={note.name} text={note.text} />
));
}
Each child in an array or iterator should have a unique "key" prop.
Check the render method of NotesList. See https://fb.me/react-warning-keys for more information.
function NotesList({ notes }) {
return notes.map(note => (
<Note key={note.id} name={note.name} text={note.text} />
));
}
DOM управляет текущим состоянием компонента
class Form extends React.Component {
inputRef = input => this.input = input
handleSubmit = () => this.makeSomeApiRequest(this.input.value)
render() {
return (
<div>
<input ref={this.inputRef} />
<button onClick={this.handleSubmit}>
Отправить
</button>
</div>
);
}
}
class Form extends React.Component {
inputRef = input => this.input = input
handleSubmit = () => this.makeSomeApiRequest(this.input.value)
render() {
return (
<div>
<input ref={this.inputRef} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
class Form extends React.Component {
inputRef = input => this.input = input
handleSubmit = () => this.makeSomeApiRequest(this.input.value)
render() {
return (
<div>
<input ref={this.inputRef} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
React управляет текущим состоянием компонента
class Form extends React.Component {
state = { value: '' }
handleSubmit = () => this.makeSomeApiRequest(this.state.value)
handleChange = event => this.setState({
value: event.target.value
})
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleChange} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
class Form extends React.Component {
state = { value: '' }
handleSubmit = () => this.makeSomeApiRequest(this.state.value)
handleChange = event => this.setState({
value: event.target.value
})
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleChange} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
class Form extends React.Component {
state = { value: '' }
handleSubmit = () => this.makeSomeApiRequest(this.state.value)
handleChange = event => this.setState({
value: event.target.value
})
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleChange} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
$ npm i webpack webpack-cli babel-loader babel-preset-react
// webpack.config.js
const path = require('path');
module.exports = {
entry: './index.js',
output: {
path: path.join(__dirname, './build')
},
module: {
rules: [{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['react']
}
}]
}
};
$ webpack --config webpack.config.js
$ npm install -g create-react-app
$ create-react-app notes-app
$ cd notes-app
$ npm run start
Compiled successfully!
You can now view notes-app in the browser.
Local: http://localhost:3000/
Note that the development build is not optimized.
To create a production build, use npm run build.
notes-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── registerServiceWorker.js
notes-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
└── registerServiceWorker.js
$ mkdir notes-app && cd notes-app
$ npm install --save next react react-dom
package.json
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
./pages/index.js
export default () => <div>Welcome to next.js!</div>
$ npm run dev
DONE Compiled successfully span 1773ms
> Ready on http://localhost:3000
const { parse } = require('url');
const next = require('next');
const server = require('express')();
const app = next({ dev: process.env.NODE_ENV !== 'production' });
const render = pageName => (req, res) => app.render(req, res, `/${pageName}`);
const handleRequest = (req, res) =>
app.getRequestHandler()(req, res, parse(req.url, true));
app.prepare().then(() => {
server
.get('/notes', render('index'))
.get('/notes/:note', render('note'))
.get('*', handleRequest)
.listen(3000, () => console.log('Listening on http://localhost:3000'));
});