<MyStatistic items={[ { titile: 'abc', message: 'cde' } ]}
constructor(props) {
super(props);
const finalMouseDelay = props.mouseDelay || 300;
this.handleMouseLeave = this.handleMouseLeave.bind(this);
this.handleMouseEnter = this.handleMouseEnter.bind(this);
this.toggleHover = _.debounce(this.toggleHover.bind(this), finalMouseDelay);
this.state = { hover: false };
}
handleMouseLeave() {
this.toggleHover(false);
}
handleMouseEnter() {
this.toggleHover(true);
}
toggleHover(to) {
this.setState({ hover: to });
}
function serialize(entity) {
return JSON.stringify({ type: entity.constructor.name, data: entity });
}
function deserialize(str, types) {
var parsed = JSON.parse(str);
return types[parsed.type] ? new types[parsed.type](parsed.data) : {};
}
function User(data) {
this.id = data.id;
this.name = data.name;
}
var user = new User({ id: 1, name: 'Nik' });
console.log('User ->', user, ' instanceOf User ===', user instanceof User);
// User -> User {id: 1, name: "Nik"} instanceOf User === true
var userJSON = serialize(user);
console.log('Serialized user ->', userJSON);
// Serialized user -> {"type":"User","data":{"id":1,"name":"Nik"}}
var restoredUser = deserialize(userJSON, { 'User': User });
console.log('Deserialized user ->', restoredUser, ' instanceOf User ===', restoredUser instanceof User);
// Deserialized user -> User {id: 1, name: "Nik"} instanceOf User === true
//
Falcor is middleware. It is not a replacement for your application server, database, or MVC framework. Instead Falcor can be used to optimize communication between the layers of a new or existing application.
Store.fetchData().then( ... )
Store.on('DATA_LOADED', (data) => this.setState({ data }); //как пример
renderAlert() {
return (
<Alert bsStyle="warning" onDismiss={this.hideAlertByClick}>
<strong>Внимание</strong> - эксперементальный проект, в стадии разработки. Заявленные функции будут подключаться по мере его развития.
</Alert>
);
}
render() {
const { showAlert } = this.state;
return (
<div>
<b> Some text </b>
{ showAlert && this.renderAlert() }
</div>
);
}
functiob action1Creator() {
return (dispatch, getState) => {
fetch(...)
.then(JSON.parse)
.then((response) => dispatch(action2Creator(response)))
;
};
}
function action2Creator(response) {
return { type: 'SOME', data: response.data[12] };
}
function someReducer(state = initialState, action) {
// обычно выглядит как switch
// action - простой js-объект
// и обязательно имеет строковое поле type
switch(action.type) {
// обрабатываем действие с типом SOME_ACTION_NAME
case 'SOME_ACTION_NAME':
// берем какие-то данные из экшена и возвращаем новое состояние
// при этом менять sate нельзя!
// state.someProperty = action.newStateData <--- НЕТ!
return { ...state, action.newStateData };
// Если мы не обрабатываем действие - просто возвращаем старое состояние
default:
return state;
}
}
function someActionCreator(someArg) {
return {
type: 'SOME_ACTION_NAME',
newStateData: someArg + 5, // <-- разная логика
};
}
import thunkMiddleware from 'redux-thunk';
function createStore(initialState) {
const reducer = combineReducers(reducers);
const finalCreateStore = applyMiddleware(
thunkMiddleware // <-- добавляем middleware
)(defaultCreateStore);
return finalCreateStore(reducer, initialState);
}
function someActionCreator(someArg) {
return (dispatch, getState) => { // <-- возвращаем фукнцию, а не объект!
const someState = getState().reducerName;
return {
type: 'SOME_ACTION_NAME',
newStateData: someArg + someState,
};
};
}
actionCreator --action--> dispatch --action--> middleware --action--> store --action--> reducer --> newState
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class MyComponent extends Component {
static propTypes = {
someProp: PropTypes.string.isRequired,
someFunc: PropTypes.func.isRequired,
};
}
// Тут мы берем из глобального состояния необходимую нам часть
// В ownProps - свойства компонента. Тут могут быть например свойства от роутера
function mapStateToProps(state, ownProps) {
return {
someProp: state.someReducer,
};
}
function mapActionsToProps(dispatch) {
return bindActionCreators ({ // <-- биндим все на disptach для удобства
someFunc: (someArg) => someActionCreator(someArg + 1),
}, dispatch);
}
export default connect(
mapStateToProps,
mapActionsToProps
)(MyComponent);
// MyComponent
import shallowequal from 'shallowequal';
export default class MyComponent {
static propTypes = {
items: PropTypes.array.isRequired,
filtres: PropTypes.object.isRequired, // <-- тут можно собрать все фильтры
};
componentWillReceiveProps(nextProps) {
if(!shallowequal(this.props.filtres, nextProps.filtres)) {
loadData(filtres);
};
}
}
// MyComponentContainer
import MyComponent from './MyComponent';
function mapState(state, ownProps) {
return {
items: applyFiltres(state.someReducer.someItems),
filtres: ownProps.location.query, // <--- как пример
};
}
export default connect(mapState)(MyComponent);
Как я понял, запрос пишется в action creator при помощи промиса
// action creator
import fetch from 'isomorphic-fetch';
export default function getBook() {
// Для запросов чаще всего используется isomorphic-fetch, который возвращает promise
const promise = fetch(url, options);
return {
types: [ 'GET_BOOK-BEGIN', 'GET_BOOK-SUCCESS', 'GET_BOOK-FAILURE' ],
promise,
};
}
// reducer
import {GET_BOOK} from '../actions/books';
const booksReducer = (state = {}, action) => {
switch (action.type) {
case 'GET_BOOK-SUCCESS':
// При успешном завершении у нас установлено свойство result с ответом сервера
return action.result;
case 'GET_BOOK-FAILURE':
// При неудачном завершении у нас установлено свойство error с описанием ошибки
doSomethingWithError(action.error); // <--- просто для примера
default:
return state;
}
};
export default booksReducer;
Надо, чтобы при нажатии на элемент меню он выделялся другим цветом. Это все получилось сделать.
class MyMenu extends React.Component {
constructor(props) {
super(props);
this.handleItemClick = this.handleItemClick.bind(this);
this.state = { selectedItem: null };
}
handleItemClick(selectedItem) {
console.log('handleItemClick', selectedItem);
this.setState({ selectedItem });
}
render() {
const { items } = this.props;
const { selectedItem } = this.state;
const { handleItemClick } = this;
return (
<ul>
{ items.map( (item, key) => (
<MenuItem
key={key}
item={item}
isActive={item === selectedItem}
onClick={handleItemClick}
/>
)) }
</ul>
);
}
}