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);
Как я понял, запрос пишется в 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>
);
}
}
render() {
const {books, url} = this.props;
return (
<ul>
{books.filter(book => book.name === url).map((book, key) => (
<li key={key}>
<p>{book.name}</p>
<p><Link to={`/${book.author}`}>{book.author}</Link></p>
<p>{book.descrip}</p>
</li>
))}
</ul>
);
}
а как же тогда сделать, так, чтоб если пользователь вводит в строку значение, которое не соответсвует регулярному выражению - выполнялась функция event.preventDefault() ? ведь keyDown и keyPress для этого не подходят, так как они берут старые занчения
<input type="text" value={someValue} onChange={handleChangeSomeValue}/>
handleChangeSomeValue(e) {
const nextVal = e.currentTarget.value;
if (!isValid(nextVal)) {
return;
}
this.setState({ someValue: nextVal });
}
import styles from 'styles.less';
...
componentDidMount() {
styles.use();
}
componentWillUnmount() {
styles.unuse();
}
class MyClass {
foo = () => {
console.log('foo a = ', this.a);
}
bar = () => {
this.a = 10;
setTimeout(this.foo, 10); // Мы не биндим foo на this
}
}
const o = new MyClass();
const bar = o.bar; // и тут тоже не биндим
bar(); // выводит "foo a = 10"
this.setState({ massiv: [ ...this.state.massiv, "новый элемент" ] })
const someArr = [];
const doAjaxJob = el => fetch('some-url', .... );
const p = Promise.all(someArr.map(doAjaxJob)); // <-- сюда можно подписаться
class MyForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.addGood = this.addGood.bind(this);
this.changeGoodCount = this.changeGoodCount.bind(this);
this.state = { goods: [] };
}
handleSubmit() {
console.log('handleSubmit');
}
addGood() {
const { goods } = this.state;
this.setState({ goods: [ ...goods, { count: 0 } ] });
}
changeGoodCount(n, count) {
const { goods } = this.state;
this.setState({ goods: goods.map( (good, i) => i === n ? { count } : good ) });
}
render() {
const { goods } = this.state;
const { handleSubmit, addGood, changeGoodCount } = this;
console.log('MyForm.render() -> goods =', goods);
return (
<form onSubmit={handleSubmit}>
<div>
Имя пользователя: <input type="text" />
</div>
<div>
Телефон: <input type="text" />
</div>
<div>
{ goods.map( (good, i) => <GoodInput key={i} good={good} n={i} onChange={changeGoodCount}/> ) }
</div>
<div>
<button type="button" onClick={addGood}>Добавить что-либо</button>
</div>
</form>
);
}
}
class GoodInput extends React.Component {
handleChange(e) {
const { n, onChange } = this.props;
const count = e.currentTarget.value;
onChange(n, count);
}
render() {
const { good, n } = this.props;
return (
<div>
Количество товара {n} <input type="text" onChange={(e) => this.handleChange(e)} />
</div>
);
}
}