SPA —
веб-приложение или сайт, который загружает только одну страницу и все последующие запросы обрабатываются без полной перезагрузки страницы.
Изоморфное приложение—
приложение, которое может работать и на стороне сервера и на стороне клиента .
<div id="root"></div>
import React from 'react';
import ReactDom from 'react-dom';
class ChatTitle extends React.Component {
render() {
return (<div className="chatTitle">Заголовок</div>);
}
}
ReactDom.render(<ChatTitle/>, document.getElementById('root'));
<div id="root"></div>
import React from 'react';
import ReactDom from 'react-dom';
class ChatTitle extends React.Component {
render() {
return (<div className="chatTitle">Заголовок</div>);
}
}
ReactDom.render(<ChatTitle/>, document.getElementById('root'));
import React from 'react';
import ReactDom from 'react-dom';
const ChatTitle = () =>
<div className="chatTitle">Заголовок</div>;
}
ReactDom.render(<ChatTitle/>, document.getElementById('root'));
import React from 'react';
import ReactDom from 'react-dom';
const ChatTitle = () =>
<div className="chatTitle">Заголовок</div>;
}
ReactDom.render(<ChatTitle/>, document.getElementById('root'));
import React from 'react';
import ReactDom from 'react-dom';
const ChatTitle = () =>
<div className="chatTitle">Заголовок</div>;
}
ReactDom.render(<ChatTitle/>, document.getElementById('root'));
<div className="awesome-div">
<img src="./images/1.png"/>
<div>
JS
React.createElement(
'div',
{ className: 'awesome-div' },
React.createElement(
'img',
{ src: './images/1.png' },
null)
)
<input type="text" maxlength="30"/>
JSX <input type="text" maxLength="30"/>
<span>Я первая строка<br>А я вторая</span>
JSX <span>Я первая строка<br/>А я вторая</span>
document.getElementById("title").className="my-great-classname";
document.getElementById("title").className="my-great-classname";
class ChatTitle extends React.Component {
render() {
return (
<div className="chatTitle">Заголовок</div>
);
}
}
class ChatTitle extends React.Component {
render() {
return (
<div className="chatTitle">Заголовок</div>
);
}
}
class ChatTitle extends React.Component {
render() {
return (
<div className="chatTitle">Заголовок</div>
<div className="chatSubtitle">Подзаголовок</div> );
}
}
При рендере компонента: Unexpected identifier
<div className="greeting">Привет, ребята!</div>
React.createElement("div", { className: "greeting" },
"Привет, ребята!");
<div className={if(true){return "greeting"}}>Привет, ребята!</div>
React.createElement("div", {className: if(true){return "greeting"}},
"Привет, ребята!");
При рендере компонента: Unexpected token if
const className = 'awesome-class';
const reallyDangerousHtml = 'содержимое div без экранирования';
const innerHtml = {__html: {reallyDangerousHtml}};
<div className={className} dangerouslySetInnerHTML={innerHtml}/>
Встроенная защита от атак XSS: всё экранируется
<div dangerouslySetInnerHTML={
{__html: 'содержимое div без экранирования'}
}/>
export default class Chat extends Component {
render() {
return (
<div>
<ChatTitle/>
<ChatStream/>
<ChatMessageBox/>
</div>
);
}
}
export default class Chat extends Component {
render() {
return (
<div>
<ChatTitle/>
<ChatStream/>
<ChatMessageBox/>
</div> );
}
}
export default class Chat extends Component {
render() { return (<ChatMessage/>); }
}
import UserIcon from '../UserIcon';
import MessageTitle from '../MessageTitle';
import MessageContent from '../MessageContent';
class ChatMessage extends React.Component {
render() {
return (<div className="chatMessage">
<UserIcon/>
<MessageTitle/>
<MessageContent/>
</div>);
}}
export default class Chat extends Component {
render() {
return (<ChatTitle chat="English"/>);
}
}
class ChatTitle extends React.Component {
const {chat} = this.props;
render() {
return (<div className="chatTitle">{chat}</div>);
}
}
export default class Chat extends Component {
render() {
return (<ChatTitle chat="English"/>);
}
}
class ChatTitle extends React.Component {
const {chat} = this.props;
render() {
return (<div className="chatTitle">{chat}</div>);
}
}
class ChatTitle extends React.Component {
render() {
return (<div className="chatTitle">{this.props.title}</div>);
}
}
ChatTitle.propTypes = {title: React.PropTypes.string};
ChatTitle.defaultProps = {title: ''};
Дополнительная информация про PropTypes
class ChatTitle extends React.Component {
render() {
return (<div className="chatTitle">{this.props.title}</div>);
}
}
ChatTitle.propTypes = {title: React.PropTypes.string};
ChatTitle.defaultProps = {title: ''};
Дополнительная информация про PropTypes
export default class Chat extends Component {
render() {
return (<ChatTitle>
English
</ChatTitle>);
}
}
class ChatTitle extends React.Component {
const {children} = this.props;
render() {
return (<div className="chatTitle">{children}</div>);
}
}
export default class Chat extends Component {
render() {
return (<ChatTitle>
English
</ChatTitle>);
}
}
class ChatTitle extends React.Component {
const {children} = this.props;
render() {
return (<div className="chatTitle">{children}</div>);
}
}
constructor(props) {
// ...
this.state = {
isLoading: true,
hasError: false
};
}
export default class ChatMessageBox extends Component {
constructor() {
super(...arguments);
this.refInput = ref => {this._input = ref;};
}
render() {
return <input type="text" ref={this.refInput}/>;
}
}
export default class ChatMessageBox extends Component {
constructor() {
super(...arguments);
this.refInput = ref => {this._input = ref;};
}
render() {
return <input type="text" ref={this.refInput}/>;
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('Отправлено значение: ' + this.input.value);
event.preventDefault();
}
...
class Form extends React.Component {
...
render() {
return (<form>
<input
type="text"
ref={(input) => this.input = input}
/>
<input
type="submit"
onSubmit={this.handleSubmit}
value="Отправить"
/>
</form>);
}
}
class Form extends React.Component {
...
render() {
return (<form>
<input
type="text"
ref={(input) => this.input = input}
/>
<input
type="submit"
onSubmit={this.handleSubmit}
value="Отправить"
/>
</form>);
}
}
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
...
class Form extends React.Component {
...
render() {
return (<form>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
<input type="submit" value="Отправить" />
</form>);
}
}
import ChildComponent from '../ChildComponent';
class ParentComponent extends React.Component {
getChildContext() {
return {color: 'purple'};
}
render() { return <ChildComponent/> }
}
ParentComponent.childContextTypes = {
color: React.PropTypes.string
};
import ChildComponent from '../ChildComponent';
class ParentComponent extends React.Component {
getChildContext() {
return {color: 'purple'};
} render() { return <ChildComponent/> }
}
ParentComponent.childContextTypes = {
color: React.PropTypes.string
};
class ChildComponent extends React.Component {
render() { return this.context.color; }
}
ChildComponent.contextTypes = {
color: React.PropTypes.string
};
class ChildComponent extends React.Component {
render() { return this.context.color; }
}
ChildComponent.contextTypes = {
color: React.PropTypes.string
};
<ul>
<li>Спать</li>
<li>Кушать</li>
</ul>
После
<ul>
<li>Учиться</li>
<li>Спать</li>
</ul>
render() {
const items = ['Учиться', 'Спать'];
return (<ul>
{
items.map((item, i) => <li key={i}>{item}</li>)
}
</ul>);
}
Использование индекса массива в качестве ключа
опасно и может привести к коллизиям!
Подробнее
Redux— это схема обработки данных в приложении.
Основана на Flux.
// action
const SELECT_CHAT = 'CHATS@@SELECT_CHAT';
// action creator
export function selectChat(chat) {
return {
type: SELECT_CHAT,
payload: chat
};
}
Action | Store | Reducer | |
---|---|---|---|
Redux | Формирует действие | Хранит состояние | Функция изменения состояния |
/* /src/actions/chats.js */
// action
const SELECT_CHAT = 'CHATS@@SELECT_CHAT';
// action creator
export function selectChat(chat) {
return {
type: SELECT_CHAT,
chat
};
}
/* /src/store/initialState.js */
// initial state
export default {
chat: null,
chats: []
};
/* /src/store/index.js */
import {createStore} from 'redux';
import reducer from '../reducers/index.js';
import initialState from './initialState.js';
export default createStore(
reducer,
initialState
);
/* /src/reducers/chat.js */
const SELECT_CHAT = 'CHATS@@SELECT_CHAT';
export default function (state = null, action) {
switch (action.type) {
case SELECT_CHAT:
return action.chat;
default:
return state;
}
}
/* /src/index.js */
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import store from './store/index.js';
import App from './components/App';
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
import {connect} from 'react-redux';
import ChatsList from '../components/ChatList';
const mapStateToProps = state => {
return {
chat: state.chat,
chats: state.chats
};
};
export default connect(mapStateToProps)(ChatList);
chat и chats станут доступными в атрибутах компонента ChatList
import {connect} from 'react-redux';
import {selectChat} from '../../actions/chats.js';
import ChatsList from '../components/ChatList';
const mapDispatchToProps = dispatch => {
return {
selectChat: payload => dispatch(selectChat(payload))
};
};
export default connect(null, mapDispatchToProps)(ChatList);
selectChat станет доступными в атрибутах компонента ChatList