Ответы пользователя по тегу Redux
  • Очистить input React/Redux?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Используете ли вы с redux методы жизненного цикла (componentWillReceiveProps и тд..)

    Конечно, используем.

    У вас "инпут" не очищается, так как нет никакого кода за это отвечающего. Можете использовать например onBlur событие...

    p.s. в целом код выглядит странно немного, может намудрили. Может сделать input неконтролируемым, оставить только "this.props.onChange", а в компонент Input передавать в value - todoName... (не вникал сильно в происходящее)
    p.p.s. про контролируемые и не контролируемые компоненты на русском: раз (мини книжка по реакту, версия старая, но актуально в целом), два (переводы офф.документации)
    Ответ написан
    Комментировать
  • Как правильно добавить класс к компоненту страницы?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Не могу сказать "хорошо/плохо/как лучше", так как всего примера не вижу, но если хотим сделать "как-то еще", то
    можно использовать объект location

    Например:
    generateClassNames() {
        if (location.href.indexOf('list') {
            return '.wrapper--list'
        }
        ...
    }
    ...
    render()
    ....
    let myClass = this.generateClassNames()
    ...
    <div classNames={myClass}>
    ...


    Так же, для работы с классами, удобно использовать пакет classnames
    Ответ написан
  • Может ли redux искать и возвращать обьект из стейта?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    У вас немного размытый вопрос (не совсем понятно "отфильтровать стейт.."), но если я вас правильно понял, в вашем редьюсере вы можете приготовить все данные, чтобы в компоненте их только отображать. Редьюсер для этого и существует.

    Например, есть некий бэкэнд, который возвращает вам ответ. Вам в компоненте из этого ответа нужна всего пара полей. Следовательно, стоит из редьюсера сразу возвращать только необходимые данные.
    Ответ написан
  • React, redux, middleware какой набор инструментов и библиотек лучше использовать?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    с использованием разных библиотек для ajax запроса и это не считая jqwerry и middleware

    Про jquery, я так понимаю вы имеете ввиду $.ajax ? А вот про middleware... (может быть не до конца понимаете, что это такое?)

    По вопросам:
    1. Производительность
    А как в вашей сборке жмется конечный файл?
    сейчас собрал сборку gulp, browserify, babelify, babel + библиотеки redux и react

    Не увидел здесь uglifyJS или что-нибудь подобное...

    Многие собирают webpack'ом, (для продакшен версии используя флаг -p, который в свою очередь.. бинго! Запускает разные "сжималки" кода. Не буду вас путать, но по-моему там тоже uglifyjs)

    2. Стили
    Стили, это стили. Как вам нравится, так и пишите. Собирайте их хоть gulp'ом, хоть webpack'ом... Разницы нет.

    3. Посоветуйте, пожалуйста, сборку и набор библиотек, под задачи которые мне предстоит решить:
    К сожалению, могу только подсказать проверенную на проекте либу для построения графиков (не очень крутая и разных типов графиков не так много, но неплохо настраивается и можно быстро разобраться)

    сегодня наткнулся на мануал использования webpack и gulp одновременно на одном проекте

    Оправдан. Если вам удобно какие-то таски прогонять через gulp, почему нет? Если сможете все, что делаете gulp'ом сделать на webpacke, то используйте только его.

    P.S. По поводу сборок. Брать чужую сборку обычно вредно (так как взяли, запустили, а коснись чего - неизвестно как это работает). Особенно, если сборка большая. Вот хороший пример большой и сложной "сборки". Чтобы понять как там все работает, потребуется порядком времени. А нужно ли будет вам все то, что автор туда накрутил? Поэтому, в качестве ознакомления, можно и посмотреть.

    P.P.S. Даже минимальная create-react-app сборка имеет немало всего интересного "под капотом". Поэтому, я за то, чтобы к сборке подходили осознанно, и лучше своей - придумать сложно. Опять же, "своя" появляется далеко не сразу, поэтому просто начните делать приложение.
    Ответ написан
    Комментировать
  • Нужен совет по react и angular?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Что проще освоить новичку angular или react с redux-ом?

    Мое мнение: разницы нет

    Стоит ли переходить на angular или продолжить изучать react и redux?

    Если пишите, что понимаете angular лучше, то может тогда на нем уже стоит что-то сделать за деньги? По рынку вакансий - реакт догоняет ангуляр. Плюс в вакансиях по реакту конкуренция сейчас пониже (на мой взгляд).

    p.s. из вопроса, не понял каков уровень js... Что можете сделать на js (+ jquery и плагины?)
    Ответ написан
  • Часто вижу в коде на сайтах сделанных на react такую конструкцию, что она значит?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Это просто "продакшен" версия. В ней имена компонентов становятся такими.
    Попробуйте у себя сделать прод. сборку (например, с помощью wepback -p) и посмотрите, что получится.
    Ответ написан
  • Сортировка данных в react + redux?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Можно нормализовать данные. По этому поводу, я думаю вам будет крайне полезно посмотреть второй курс[EN] от создателя redux.

    p.s. урок про нормализацию, где рассказывается, как можно решить вашу проблему, но мне кажется, чтобы понять, потребуется посмотреть весь курс.

    p.p.s. полезные ссылки:
    1) https://rajdee.gitbooks.io/redux-in-russian/conten... (может переведут, когда-нибудь)
    2) https://habrahabr.ru/company/hh/blog/310524/ (RU)
    Ответ написан
    1 комментарий
  • Как реализовать авторизацию пользователя на стеке React Redux Node?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Пригодится jwt. (гугл)

    В общих словах: вам нужно выдать юзеру токен. С этим токеном юзер будет выполнять запросы к вашим защищенным методам api (вы можете оставить какие-то методы "без токена").

    Node.js часть
    Пример роута на логин (сделано не лучшим образом, в плане коллбэков, но что нашлось под рукой...):

    auth.js
    ...
    const v4 = require('node-uuid').v4
    const jwt = require('jsonwebtoken')
    ...
    router.post('/signin', (req, res, next) => {
    
      // валидация, например... 
    
      if (errors) {
        return res.status(400).json({ errors })
      } else {
        // поиск юзера в базе, сравнение хэша и прочие необходимые операции
        ...
       // допустим все ок, нужно ответить токеном
      // генерируем необходимые опции и сам токен
    
            const payload = {
              _id: user._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }
            const options = {
              expiresIn: '7d',
              jwtid: v4(),
            }
            const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
            jwt.sign(payload, secret, options, (err, token) => {
              // отвечаем токеном, для будущих запросов с клиента
              return res.json({ data: token })
            })
         ...
    })
    
    module.exports = router;


    Пример защищенного роута (метода, который требует токен):
    ...
    const jwt = require('jsonwebtoken')
    const Poll = require('../models/poll')
    ...
    
    const requireToken = (req,res,next) => {
      const token = req.headers['x-api-key']
      const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
    
      jwt.verify(token, secret, (err, decoded) => {
        if (err) {
          return res.status(401).json({ error: err.message })
        }
        req.params.userId = decoded._id
        next()
      })
    }
    ...
    
    // обратите внимание на requireToken - функция вызывается при каждом обращении к роуту
    // то есть при каждом PUT запросе по адресу (например: PUT api/v1/products/1238914)
    // будет вызываться requireToken
    
    router.put('/:id', requireToken, (req, res, next) => {
      const { productId } = req.body
      const userId = req.params.userId
    
      Poll.findById(req.params.id)
        .populate({ path: 'products' })
        .exec((err, poll) => {
            // ... необходимые действия в базе, в процессе успешного зачтения голоса...
        }
    })


    Клиентское приложение:

    Типичный ActionCreator (в качестве библиотеки для запросов можно взять bluebird, isomorphic-fetch, да хоть нативный xhr)
    actions/LoginActions.js

    export function login(data) {
      return dispatch => {
        dispatch({ type: LOGIN_REQUEST })
    
        // request в данном случае - https://github.com/KyleAMathews/superagent-bluebird-promise
        return request.post(`${API_ROOT_V1}/auth/signin`)
          .send(data)
          .then(res => {
            if (!res.ok) {
              dispatch({ type: LOGIN_FAILURE })
            } else {
              dispatch({
                type: LOGIN_SUCCESS,
                data: res.body.data,
              })
              //сохранение токена в localStorage
              localStorage.setItem('cks_token', res.body.data)
            }
          }, err => {
            dispatch({ type: LOGIN_FAILURE })
          })
      }
    }


    Пример голосования с токеном (выше, в node.js части был метод апи, а это PUT запрос с клиента)

    export function vote(productId, voteId) {
      return dispatch => {
        dispatch({ type: POLL_VOTE_REQUEST })
    
        return request.put(`${API_ROOT_V1}/api/v1/vote/${voteId}`)
          .set('X-API-Key', localStorage.getItem('cks_token')) // установка ТОКЕНА в заголовок 'X-API-Key'
          .send({ productId })
          .then(res => {
            if (!res.ok) {
              dispatch({ type: POLL_VOTE_FAILURE })
            } else {
              dispatch({
                type: POLL_VOTE_SUCCESS,
                data: normalize(res.body.data, schema.poll),
              })
            }
          }, err => {
            dispatch({ type: POLL_VOTE_FAILURE })
          })
      }
    }


    Надеюсь код формы с кнопкой "голосовать" не трубется.
    ====

    Все это можно организовать удобнее, например, выставлять токен всем запросам автоматически (речь про клиентскую часть):
    import fetch from 'isomorphic-fetch'
    ...
    const defaultHeaders = {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    }
    
    function buildHeaders() {
      const authToken = localStorage.getItem('TOKEN')
      return { ...defaultHeaders, Authorization: authToken }
    }
    ...
    export function httpPost(url, data) {
      const body = JSON.stringify(data)
    
      return fetch(url, {
        method: 'post',
        headers: buildHeaders(),
        body: body,
      })
      .then(... код оработки запроса ...)
    }


    ===

    Проверить наличие токена, можно с в роутере, с помощью хука на onEnter.

    root.js
    ...
    <Provider store={store}>
          <Router history={routerHistory}>
            {configRoutes(store)} // Роуты создаются функцией, чтобы можно было использовать внутри нее store.getState()
          </Router>
        </Provider>
    ...


    routes.js
    export default function configRoutes(store) {
      function _ensureAuthenticated(nextState, replace, callback) {
        const { dispatch } = store
        const { session } = store.getState()
        const { currentUser } = session
        let nextUrl
    
        if (!currentUser && localStorage.getItem('cks.token')) {
          dispatch(getCurrentAccount())
        } else if (!localStorage.getItem('cks.token')) {
          replace('/signin')
        }
        callback()
      }
    
      return (
        <Route path='/' component={App}>
          <Route path='/signin' component={SigninContainer} />
          <Route path='/signup' component={SignupContainer} />
    
          <Route path='/locked' component={AuthenticatedContainer} onEnter={_ensureAuthenticated}>
            <Route component={LockedArea}>
              <Route path='/locked/a' component={A} />
              <Route path='/locked/b/:id' component={B} />
              <Route path='/locked/c' component={C} />
            </Route>
          </Route>
        </Route>
      )


    Остается только создать AuthenticatedContainer в котором проверять: есть ли currentUser (в рамках этого примера) и если нет - возвращать false. А если есть - this.props.children (в которых будут дальнейшие роуты..)
    ===

    Итого:
    1) у вас есть API написанное на node.js.
    2) У этого API есть защищенные методы, которые проверяют наличия токена в http-запросе. Токен выдается при запросе на логин. Само собой, операция логина (то есть POST запрос на your-api/login) не требует токена.
    3) После удачного логина, вы получаете в ответе на свой запрос токен (это уже внутри клиентского кода, и если мы говорим о redux - то внутри асинхронного вызова в actions)
    4) Сохраняете токен (например, в localStorage)
    5) Во все необходимые http-запросы устанавливаете заголовок с токеном
    Ответ написан
    15 комментариев
  • Как получить доступ к всему store из reducer?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    - combineReducers можно использовать не только на корневом уровне.
    - попробуйте не заморачиваться "правильно / не правильно", а просто делать как вам удобно, и если начинают возникать трудности - переделывать.

    P.S. круто про редьюсеры рассказано во втором туториале от Дэна (создателя redux). Так же можно и первый посмотреть, если еще не смотрели (оба на английском, но речь понятная + к каждому видео есть транскрипция (текст))
    Ответ написан
    Комментировать
  • Как вы структурируете компоненты в react приложениях?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Есть директория components, есть containers. Внутри почти плоский список, когда появляется какая-то явная группа, например 5 компонентов фильтров - создаю отдельную поддиректорию.

    Предлагаю вам не заморачиваться по этому поводу сильно .)
    Ответ написан
    Комментировать
  • Стоит ли использовать state, или все таки всегда хранить в redux store?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    State можно и нужно использовать. Об этом не раз говорил создатель библиотеки Redux.

    Согласен с Pavel Shvedov по поводу того в каких случаях. Абсолютно нет никакой необходимости тот же onChange в поле инпута выносить в redux store и диспатчить изменения на каждый чих, если вы, например, делаете валидацию поля. Пусть у вас будет форма, у нее есть кнопка submit, для нее, например, простейшее правило: все три поля формы должны быть не пустыми. Надо ли это выносить в store? Зачем? Используете state, смотрите: если поля не пустые - убираете атрибут disabled у кнопки submit. Смотрите === реакт сам смотрит, в зависимости от переменной в state, так как на изменения state происходит ре-рендер компонента.

    Пример:

    ...
    constructor(props) {
        super(props)
        this.state = {
          email: '',
          password: '',
        }
        this.onSubmit = this.onSubmit.bind(this)
        this.onInputChange = this.onInputChange.bind(this)
      }
      onSubmit(e) {
        e.preventDefault()
        const { email, password } = this.state
        this.props.onSubmit(email, password)
      }
      onInputChange(e) {
        this.setState({ [e.target.id]: e.target.value })
      }
      validate() {
        if (this.state.email && this.state.password) {
          return true
        }
      }
    ...


    далее в методе render компонента:

    render() {
        const { email, password } = this.state
        return (
          <div className='row'>
            <div className='centered w300'>
              <form onSubmit={this.onSubmit}>
                ...
                <button type='submit' className='btn btn-success' disabled={!this.validate()}>
                  Submit
                </button>
              </form>
            </div>
          </div>
        )
      }


    Если не требуется большего, то зачем при этом использовать store ? На случай для какой-то более сложной валидации, можно использовать onBlur события и их уже диспатчить (вдруг вы введеный ник проверяете на "занят/не занят").
    Ответ написан
    2 комментария
  • Как в связке Redux + React.js кешировать ответы сервера и где?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Как вам уже написал Aves в компоненте перед вызовом экшена проверяйте, если данные уже есть - не делайте запрос. Выглядеть может так:

    loadData() {
      if (state.data.length) {
        // ничего не делай
      } else {
        this.props.callActionAndLoadData()
      }
    }
    Ответ написан
    Комментировать
  • Не срабатывает onchange в React Datepicker?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    У вас на onChange функция, которая просто форматирует дату. И все, я даже затрудняюсь сказать, какой от этого будет эффект, но помоему никакой.

    Нужно на onChange прокидывать функцию - создатель действия, например, у нас это будет myAction.

    Следовательно, где-то там в actions будет примерно такой код:

    export function myAction(date) {
      return {
        type: 'CHANGE_DATE',
        data: date
      }
    }


    Затем где-то в редьюсере, должно быть соответствующее условие, например, на case 'CHANGE_DATE' у вас будет устанавливаться в current дата. (специально не пишу код, чтобы немного поработали сами).

    В конце концов, в вашем контейнере, у вас должны быть mapStateToProps и mapDispatchToProps примерно такого вида:

    const mapStateToProps = (state) => ({
      dates: state.dates,
    })
    
    const mapDispatchToProps = (dispatch) => ({
      myAction: (date) => dispatch(myAction(date)),
    })


    Ну и само подключение DayPickerSection будет выглядеть примерно так:

    <DayPickerSection selected={this.props.dates.current}  myAction={this.props.myAction} />


    А в рендере (имеется в виду в рендере DayPickerSection) будет следовательно:

    const DayPickerSection = ({selected, myAction}) => {
        return (
            <div>
                <DatePicker selected={selected}
                            onChange={(date) => myAction(date) }/>
            </div>
        );
    };


    Итого (читать медленно): в onChange компонента DatePicker попадет свойство this.props.myAction "прокинутое" в DayPickerSection. В свою очередь, в DayPickerSection это свойство будет равно функции, которая будет "прокинута" с помощью mapDispatchToProps в this.props контейнера. Контейнер, называйте его как хотите, в нашем случае это родительский элемент, например, который "приконекчен" (c помощью функции connect), и который из-за этого принимает к себе в this.props данные описанные в mapStateToProps и в mapDispatchToProps, которые в свою очередь являются чем то вроде карты. То есть, в конечном счете в this.props.myAction вашего контейнера попадет функция myAction из вашей папки actions. Конечно, для этого ее нужно импортировать в начале файла (import { myAction } from '../actions'.)

    Контейнер может выглядеть так:

    import React, { Component } from 'react'
    import { connect } from 'react-redux'
    import { myAction } from '../actions'
    
    class App extends Component {
      render() {
        const { dates, myAction } = this.props
    
        return (
          <div className='my-app'>
            <DayPickerSection selected={dates.current}  myAction={myAction} />
          </div>
        )
      }
    }
    
    const mapStateToProps = (state) => ({
      dates: state.dates,
    })
    
    const mapDispatchToProps = (dispatch) => ({
      myAction: (date) => dispatch(myAction(date)),
    })
    
    export default connect(mapStateToProps, mapDispatchToProps)(App)
    Ответ написан
    1 комментарий
  • Что с react-datepicker?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Наверное, забыли подключить файл со стилями.

    require('react-datepicker/dist/react-datepicker.css');
    Ответ написан
    7 комментариев
  • Datepicker React/Redux?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Универсальный рецепт для любых сторонних компонентов.

    1. Сторонний компонент, если он хороший, обычно ничего не знает о данных. Он их только отображает. Это то что нам нужно.

    2. Раз компонент ожидает от нас данные, мы должны их в него передать. Например в контейнере СтраницаБилетов, у вас подключается компонент ВыборДаты. Супер, чтобы в ВыборДаты передать данные используются props. Будет примерно так:
    <ВыборДаты текущаяДата={Дата_из_стора/или роута} />

    либо EN вариант:
    <DatePicker current={myDate} />

    3. Далее, у стороннего компонента (опять же, если он хороший) наверняка, есть какой-то onChange обработчик. Предположим, что он называется onDateChange. Следовательно, мы в контейнере подключаем AC (создатель действия, экшен), и передаем его в компонент. Выглядеть будет примерно так:
    <DatePicker onDateChange={this.props.getTickets} />


    либо русский вариант (просто для понимания, вдруг пригодится)
    <ВыборДаты текущая={мояДата} onDateChange={this.props.загрузиБилеты} />


    Причем, функция загрузки новых билетов для этой даты, это не что иное, как экспортируемая функция из папки с вашими экшенами.
    ---

    Приведу пример с кодом, хотя так как я его вытащил с реального проекта, он может вас запутать некоторой сложностью:

    Это мой компонент DayPicker, который внутри себя подключает компонент DatePicker
    class DayPicker extends Component {
      constructor(props) {
        super(props)
        this.state = {
          start: null,
        }
      }
      componentWillMount() {
        const { startTime } = this.props
        this.setState({ start: startTime })
      }
      componentWillReceiveProps(nextProps) {
        const { startTime } = nextProps
        this.setState({ start: startTime })
      }
      render() {
        const { start } = this.state
        const { onDateChange } = this.props
    
        return (
          <section>
            <div className='date-picker'>
              <DatePicker
                className='form-control'
                placeholderText={'Введите дату'}
                selected={moment(start)}
                onChange={ (moment) => onDateChange('startTime', moment) }/>
            </div>
          </section>
        )
      }
    }


    Тем не менее, это компонент. И он должен как-то получать в себя данные. Это происходит в контейнере, кода там много, приведу кусочек:

    // обработчик onDateChange
    onDateChange(dateField, moment) {
      const query = this.props.location.query
      const nextQuery = {
        ...query,
        [dateField]: moment.format('YYYY-MM-DD'),
      }
      // так как у меня все завязано на роутинге, здесь другой вызов ниже,
      // но для простоты примеры, здесь необходимо вызвать экшен, например getTickets(dateField)
    }
    
    // это находится в render функции
    const { startTime } = this.props
    
    <div className='row row-margin'>
      <div className='col-md-12'>
        <DayPicker
          onDateChange={this.onDateChange}
          startTime={startTime}
        />
      </div>
    </div>
    
    // ваш экшен getTickets(dateField) наверняка подключается так
    import { getTickets } from '../../actions/TicketsActions'
    //...
    const mapDispatchToProps = (dispatch) => ({
      getTickets: (dateField) => dispatch(getUsers(dateField)),
    })
    //...
    
    // ваша переменная startTime наверняка приходит из редьюсера / роута, у меня из роута
    const mapStateToProps = (state, ownProps) => ({
      startTime: ownProps.location.query.startTime,
    })
    Ответ написан
    8 комментариев
  • Как поставить 2 redux thunk на разные редюсеры?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Не совсем понял ваш вопрос, но thunk middleware никак не влияет на редьюсер.

    Redux-thunk - это всего лишь вспомогательная функция для ваших экшен-крейтеров (или просто экшенов, как удобнее). Если посмотреть на исходный код, то можно описать его так: если AC (экшен, экшен крейтор, создатель действия...) возвращает простой объект - прокидывай его дальше, если возвращает функцию, то "прокинь" в эту функцию dispatch и getState функции в качестве аргументов. Например, это дает нам возможность работать с асинхронными запросами. Так как, чтобы достучаться до reducer'a мы же должны использовать функцию dispatch. А если бы не было redux-thunk, то откуда бы она взялась у нас в коде экшена: импорта в файл нет, нигде не описано, что const dispatch = ...?

    Приведу пример:

    export function logout {
      return {
        type: LOGOUT_SUCCESS,
      }
    }


    AC возвращает простой объект, который (если нет других middleware влияющих на работу) - сразу попадает в reducer.

    export function login(data) {
      return dispatch => {
        dispatch({ type: LOGIN_REQUEST })
    
        return request.post(`${API_ROOT_V1}/auth/signin`)
          .send(data)
          .then(res => {
            if (!res.ok) {
              dispatch({ type: LOGIN_FAILURE })
              dispatch(showNotification({
                status: 'err',
                text: 'something going wrong',
              }))
    
            } else {
              dispatch({
                type: LOGIN_SUCCESS,
                data: res.body.data,
              })
              localStorage.setItem('cks_token', res.body.data)
              dispatch(push('/'))
            }
          }, err => {
            dispatch({ type: LOGIN_FAILURE })
            dispatch(showNotification({
              status: 'err',
              text: err.body && err.body.error || err.message,
            }))
          })
      }
    }


    Особое внимание на return dispatch => { - это значит, что АС возвращает функцию, а следовательно в этой функции из-за redux-thunk доступен dispatch. Если вводит в заблуждение ES2015 синтаксис, то это можно было бы написать как return function(dispatch) { ...

    P.S. Опишите подробнее, что вы имеете в виду под "А как разделить логику обработки?"
    Ответ написан
    Комментировать
  • React + Redux, как начать правильно?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Как с этим работать, чтобы не сойти с ума?

    Не торопиться, если хочется вдумчиво разобраться =)

    Первая проблема, как принять данные?

    Использовать react lifecycle hooks: в момент componentDidMount (или в componentWillMount) вызвать actionCreator (AC = создатель действия) -> в AC вы генерируете событие с типом REQUEST (которое ловит ваш редьюсер), а затем производите "ajax запрос", скажем так. В случае удачного результата - генерируете событие SUCCESS и ваш редьюсер устанавливает данные. Далее, ваш компонент формы, видит, что есть новые "props" (свойства, которые изменились в редьюсере, о которых компонент узнал, так как он приконекчен с помощью функции "connect" из библиотеки react-redux) и запускается перерендер. Вуаля, после такой кучи действий ваша форма "приняла данные".

    Конечно, если просто сделать нативный xhr запрос, кода будет гораздо меньше и все в одном файле, но это уже нужно исходить из ваших пожеланий. Если вам нужно, чтобы данные были "прогнаны" через редьюсер и оказались в store, значит "много действий". Если не нужно - просто обычный xhr запрос, либо если угодно $.ajax и установка данных в state компонента.

    Например, на onchange селекта мне нужно брать данные с него, что-то считать и выводить в какой-то инпут... какая здесь цепочка действий, и главное в каких файлах?


    Если используется redux, то цепочка следующая: на onChange селекта вызывается обработчик, то есть функция в вашем компоненте, которая вызывает AC (создатель действия, который располагается в папке actions). Далее уходит запрос на сервер. Затем с сервера приходит успешный ответ - вы генерируете событие, типа "DATA_RESPONSE_SUCCESS" и ваш редьюсер его "ловит". Итак, вы оказываетесь в третьем файле - в файле с редьюсером. Там вы манипулируете данными, так как вместе с типом события, вы так же должны были передать из action'а и данные, которые пришли с сервера. После того, как вы установите новые данные в редьюсере - начинается магия (которая заключается в том, что ваш компонент слушает изменения в объекте стора, с помощью функции connect). Ваш компонент перерендеривается и в инпуте оказываются нужные данные, так как инпут в качестве value использует, например: this.props.myNewValueFromServerAfterSelectManipulation (имя переменной, конечно, шуточное).

    Итого: вы потрогали файл компонента, файл из папки actions и файл из папки reducers.

    Супер итого:
    1) вам нужно понять, как сделать форму без redux. Как в ней с помощью this.state и методов жизненого цикла устанавливать и изменять данные в зависимости от того, что выбрал/ввел пользователь. Сделать это не сложно, если начать с туториала на официальной странице, либо заглянуть в РУ туториал здесь.

    2) вам нужно понять, почему в actions располагаются асинхронные запросы, и как при этом работает redux-thunk (а так же middlewares в общем). Почему в reducers производится только изменение данных. И самое главное, почему компонент при этом перерисовывается. Опять же, ссылки на официальные руководства уже дали. Русский перевод там не закончен, поэтому, хоть и устаревают версии библиотек, этот туториал по редуксу до сих пор актуален.

    P.S. в туториалах есть примеры с кодом
    Ответ написан
    3 комментария
  • Накидайте больших примеров react & redux приложений?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Не знаю насколько большие, но внимание уделить им стоит:

    https://github.com/WebbyLab/itsquiz-wall
    www.robinwieruch.de/the-soundcloud-client-in-react... (git)

    в остальном: разрастается папка с экшенами и редьюсерами, появляется папка с какими-то хелперами (функциями, которые используются в разных компонентах, например форматирование даты в ЧЧ:ММ:СС из секунд...), появляется больше зависимостей (как и на всех других проектах). Приходится писать больше тестов и сборка/пересборка происходит медленнее.
    Ответ написан
  • Как можно переключить страницу исползуя React Router после получения данных?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Можете решить прелоадером. Пока нет данных - рисуете прелоадер (строку "загружаю...", часики, или что еще).
    Ответ написан
    1 комментарий
  • Пробрасывание функций из actions через дерево компонентов vs connect функций в компоненте?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Добрый день.

    Везде использую connect. Почему? Потому что "пробрасывание через дерево" - не видел в оригинальной документации, а так же вообще не видел. Имеется ввиду использование context?

    Мне нравится connect, все устраивает.

    В записи для connect (а точнее для mapDispatchToProps) использую или не использую bindActionCreators:
    const mapDispatchToProps = (dispatch) => ({
      pollActions: bindActionCreators(PollActions, dispatch),
    })


    const mapDispatchToProps = (dispatch) => ({
      getUsers: (params) => dispatch(getUsers(params)),
      dispatch,
    })


    P.S. покажите пример с пробрасыванием функций из actions через дерево компонентов, и если уже что-то интересное для себя в этом подходе выделили - напишите. Будем смотреть вместе.
    Ответ написан