Ответы пользователя по тегу Redux
  • Как вывести данные с сервера без lodash?

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

    return Object.keys(this.props.posts).map(postId => {
          const currentPost = this.props.posts[postId]
          return (
            <li className="list-group-item" key={currentPost.id}>
              <span className="pull-xs-right">{currentPost.categories}</span>
              <strong>{currentPost.title}</strong>
            </li>
          );
        })
    Ответ написан
    Комментировать
  • Как реализовать грамотную проверку авторизации?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Вы используете react-router? Если да, то тут все просто:
    1) роуты создаются с помощью функции, таким образом вы можете прокинуть в роутинг store
    ...
    import configRoutes from '../../routes'
    ...
    render() {
      return (
        <Provider store={store}>
          <Router history={routerHistory}>
            {configRoutes(store)}
          </Router>
        </Provider>
      )
    }


    2) Далее в роутинге, устанавливаете на "защищенные" компоненты onEnter hook:
    ...
    <Route path='/secret-area' component={SecretAreaContainer} onEnter={_ensureAuthenticated}>
    ...


    3) сама функция, смотрит есть ли в store необходимые данные:
    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('token')) {
            dispatch(getCurrentAccount())
          }
        } else if (!localStorage.getItem('token')) {
          nextUrl = location.pathname + location.search.replace('?', '&')
          replace('/signin')
        }
    
        callback()
      }
    
      // здесь ваши роуты


    Ок, по роутам готово.

    Теперь, по переадресации:
    - на success в логине, делаете редирект куда угодно:
    export function signIn(email, password) {
      return (dispatch, getState) => {
    
        dispatch({
          type: USER_SIGN_IN_REQUEST,
        })
    
        const params = {
          email,
          password,
        }
    
        httpPost(`${API_ROOT_V1}/api/authenticate`, params)
          .then((data) => {
            saveParamsToLS(data) // здесь токен можно сохранить, например
            dispatch(push('/account')) // ваш РЕДИРЕКТ, используется push из react-router-redux (что необязательно)
          })
          .catch((error) => {
            console.warn(`Sign in error: ${JSON.stringify(error)}`) //eslint-disable-line no-console
            dispatch({
              type: USER_SIGN_IN_FAILURE,
              error: error,
            })
          })
      }
    }


    и остается кейс с прямым заходом: вы должны разрулить это опять же в onEnter хуке в роутере. Так как у вас есть store, и вам доступны все данные из него, включая store.dispatch метод, добить пример не составит труда.
    Ответ написан
    3 комментария
  • Как работает использование Redux вместе со state?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    В вашем примере, нет главного - как вы отрисовываете минуты/часы? Через state или через props? Redux не важно используете вы state или нет, реакт-компоненту - не важно используете вы redux или нет.

    Обновлять state на основе пришедших с помощью Redux props вы можете в componentWillReceiveProps
    Ответ написан
    5 комментариев
  • Redux thunk, откуда береться dispatch в экшине?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Он берется из middleware redux-thunk

    Посмотрим на исходный код:

    function createThunkMiddleware(extraArgument) {
      return ({ dispatch, getState }) => next => action => {
        if (typeof action === 'function') {
          return action(dispatch, getState, extraArgument);
        }
    
        return next(action);
      };
    }


    В котором видно, что если возвращаемый тип действия - function, то вызови все тоже самое, но с аргументами (dispatch, getState и extraArgument) - которые доступны через область видимости и являются тем "что надо".

    ca799e34804e4ae7afeaffa56751700d.jpg
    Ответ написан
    4 комментария
  • Нужна лучшая практика что бы убрать писанину в action?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Сначала тоже казалось "писанина", смотрел в сторону разных middleware'ов и т.д.
    А потом понял - что тут проблемы лично для меня никакой нет. Открываешь старый проект, на котором нашли баг/нужно что-то добавить - и вот оно, все просто по полочкам: есть действие пользователя -> есть action creator -> есть action с определенным типом -> есть reducer ... Достаточно 10 минут, чтобы освежить в памяти "что откуда и куда", поэтому я решил не придумывать и не усложнять.
    Ответ написан
    Комментировать
  • Angular 2 и Redux?

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

    1) Не увидели относительно чего? Относительно flux / mobx / etc.. ?
    2) Или просто Redux vs setState для всех данных в приложении? (сарказм) Это я к чему, у вас было либо маленькое приложение (очень маленькое), либо вы чего-то не поняли. Если же относительно п.1 - то дополните вопрос
    Ответ написан
  • Почему в React созданные функции(методы) вызываются без аргументов?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    // для примера обе переменные (store и dispatch) объявлены в той же области видимости
    // на самом деле их нет в вашем файле компонента
    // Так как функция connect вызывается "где-то там, где они доступны"
    // вы имеете к ним доступ
    let dispatch = () => console.log("dispatch")
    let store = { user: { name: 'Mike', age: 15 }, data: [1,2,3] }
    
    function connect(mapStateToProps, mapDispatchToProps) {
      console.log(mapStateToProps(store))
    }
    
    function mapStateToProps(storeFromClosure) { // здесь оказывается глобальный store доступный из замыкания
      return {
        myData: storeFromClosure.data 
      }
    }
    
    connect(mapStateToProps, null)
    Ответ написан
  • Как кастомизировать сторонний компонент React?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Сторонний компонент, это обычно всего лишь "вьюха". Хорошие компоненты, таковыми и являются (пример) (react virtualized)

    Чтобы передать в него свойства - мы просто передаем свойства. Опять же, в качестве примера (react select 2). Передаем в него, например, options.
    Так же, у этого "хорошего" компонента, на изменение автором задуман onChange..
    <Select
    	name="form-field-name"
    	value="one"
    	options={options}
    	onChange={this.setUser} // тот самый onChange
    />

    Уже в нем можно смело "дергать" экшен-крейтор родителя, банально:
    // текущий компонент
    setUser(e) { this.props.setUser(e.target.value) }
    // родитель
    setUser(id) { this.props.actions.setUser(id) } // вызов redux action-creator


    В любом случае, вариантов обратится из потомка к родителю всего два. Причем первый используется в 90% случаев - это передать в props функцию-обработчик.
    Второй вариант, созданием компонентов-оберток используется реже и обычно уже на каких-то замороченных ситуациях.
    Ответ написан
    Комментировать
  • Какой необходимый уровень знаний для junior React.js Разработчика?

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

    не включая основы js

    Извините, но стандартная задача, про "напишите функуцию add, которая при вызове add(1)(2) вернет 3" - многих положила на лопатки =) Поэтому будьте готовы..

    React
    0) Какую проблему решает react ?
    1) Мгновенно ли срабатывает setState? Если нет, то как выполнить код, который 100% выполнится после того, как новый state будет установлен?
    2) Зачем многие постоянно пишут в constructor: this.FUNCTION_NAME = this.FUNCTION_NAME.bind(this) и отсюда вопрос вытекает чему равно this в разных местах вашего компонента...
    3) в каких методах жизненого цикла стоит выполнять xhr запросы? В каких стоит "обновлять state на основе props"?
    4) Что будет если вызвать this.setState в render методе компонента?
    5) зачем нужен componenWIllUnmount, приведите пример..
    6) Контролируемые, не контролируемые компоненты
    7) Как организовать роутинг в реакт приложении? (ответ: взять react-router - подходит, но было бы круто, если бы вы рассказали, как он примерно работает)*
    8) Зачем нужны propTypes? Что происходит с ними в production сборке?
    9) Как можно удобно "отлаживать" чужой код приложения, написанного на react (намек в сторону React devtools)
    ...

    Redux
    0) Какую проблему решает redux?
    1) Зачем многие создают типы действий NAME_REQUEST / NAME_SUCCESS ? А заодно, что такое "действие", а что такое "создатель действия"...
    2) Что такое редьюсер? Можете написать простой редьюсер без react/redux?*
    3) Для чего нужен redux-thunk? Как он работает? Напишите (можно псевдокод) асинхронный создатель действия (либо, если надоело говорить "терминами" - асинхронный aciton)
    4) Как компоненты приложения получают "пропсы" из "стора"?*
    5) Можно ли (и считается ли это нормальным) использовать state, если используется Redux?
    6) Почему в reducer'ax мы возвращаем новые объекты? Приведите пример, когда вы возвращаете новый объект, а когда тот же самый.
    6.5) А так же, "как в js вообще это работает?". Например:
    let obj1 { name: 'Test', age: 100 }
    let obj2 = obj1
    obj2.name = 'Test_new'

    Что будет в obj1, почему? В каких случаях объекты могут быть равны?
    7) Что возвращает функция connect (из react-redux)?
    ...

    Общее:
    0) package.json
    1) Webpack, gulp, etc...
    2) node.js
    3) promise

    Что-нибудь практическое:
    1) Как бы вы валидировали форму, если ошибки валидации приходят после submit'a ее на сервер..
    2) Почему не работает следующий код, сделайте чтобы работало
    ...
    На истину не претендую, но такие вопросы имели место быть на собеседованиях. В беседе можно многое разузнать дополнительными вопросами и так далее. Так же, если часть вопросов вам неизвестна - не беда, многие и на половину ответить не могут.

    p.s. возможно дополню...
    p.p.s. звездочкой отметил, на мой взгляд не самые необходимые для junior-собеседования вопросы.
    Ответ написан
    31 комментарий
  • Какая правильная организация react-redux приложения?

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

    Есть меню(не навигация, а просто набор плюшек, к примеру добавить заметку) и сама область где отображается эта заметка.

    Почему этот "набор плюшек" не завязать на "навигации" ?
    То есть "добавить заметку" -> /add, редактировать -> /edit/:id .. ? В любом случае, вы сами пишите о 2х областях, которые есть на всех страницах, значит у вас должен быть родительский компонент, в котором рендерится "шапка (меню это или нет, не важно) + рабочая область"

    Получается, если вы все же за идею с роутером, то примерный код будет таким:
    App.js
    ...
    <HeaderContainer /> // (или тупой <Header />)
    { this.props.children }
    ...


    Внутри children, само собой разумеется - то, что возвращает ваш роутинг, значит, код роутера примерно такой:
    ...
    <Route path='/add' component={AddContainer} />
    <Route path='/edit/:id' component={EditContainer} />
    ...


    Когда я говорю "контейнер", значит я подразумеваю (как и все остальные), что это компонент, который присоединен к redux ( то есть
    connect(mapStateToProps,mapDispatchToProps)(имя_компонента)
    ).

    Таким образом, мы уже решили вашу задачу про: Меню при вызове запускает компонент конкретной задачи. тот отправляет результат на рабочий стол и там оно хранится , так как у нас в меню все сделано с помощью Link из react-router'a, и наша рабочая область изменяется вместе с URL-адресом браузера. Если есть необходимость, все клики по меню "прогонять" через ActionCreators (AC) выполняя какие-то дополнительные действия, или просто "для порядка" - то вы можете использовать внутри ваших AC push из react-router-redux, выглядит это обычно так:
    dispatch(push('/newUrl'))

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

    ---
    И еще. думаю вынести все данные(пункты меню к примеру) в отдельный файл(этакий недосервер)
    Где с ним лучше общаться? использую react-redux

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

    Как уже сказано, в конце не пойму о чем вы пишите... Структура "ответа с сервера" ? или о чем речь? Зачем вам компонент, который будет приводить структуру в нужный вид? и тд.

    ---
    Напоследок:

    Да и мне примеры вовсе не нужны. хочу для начала своих шишек набить.
    НО точно не хочу пару месяцев пилить проект(бесконечно усложняющаяся toDo) а потом понять что привык делать так как не надо.

    Никакого привыкания "делать, как не надо" - не бывает. Вы сначала делаете так, как считаете наилучше возможным, в процессе, что-то подпиливая, потом приходит озарение/совет - вы понимаете, что так будет лучше и делаете дальше. Если программист знает как "сделать лучше", но при этом делает "как привык" то грошь ему цена.
    Ответ написан
    8 комментариев
  • Как в react-redux реализовать вызов метода в ответ на изменение стейта?

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

    Представим ваш action creator (функцию), которая на success возвращает успешную авторизацию, например:
    $.ajax(url...
      success(data) { dispatch({type: AUTH_SUCCESS, data }) })


    Кто мешает сделать так?
    $.ajax(url...
      success(data) { 
        dispatch({type: AUTH_SUCCESS, data }) 
        loadUserCart(data.user_id) // <- еще один action creator
    })

    Суть уже понятна? Мы после успешной авторизации юзера, вызываем сразу же следующий экшен-крейтор:
    function loadUserCart(id) {
      return (dispatch) => {
        
        dispatch({ type: CART_REQUEST }) // получается, это событие вызовется сразу после успешной авторизации, практически мгновенно
    
        
        $.ajax(urlForCartUpdate...
          success(data) { 
            dispatch({type: CART_SUCCESS, data })
        })  
      }
    }


    Далее вы в компоненте с корзиной, настраиваете показ прелоадера, и вуаля! Получается, для юзера, без задержек, как только он авторизовался - у корзины будет крутиться прелоадер. Юзеру все понятно, он занимается своими делами. Как только "данные подъехали" - вы скрыли прелоадер и показали ему необходимые данные по корзине.

    нужно сначала сделать AJAX-запрос, а по его результатам уже рендерить корзину

    Именно это мы и сделали.

    P.S. не знаю, требуется ли это, но на всякий случай укажу, что чтобы сделать прелоадер в шаблоне, вам нужно в редьюсере корзины создать какое-нибудь поле (флаг), например isLoading и устанавливать его в true когда получите action с типом CART_REQUEST, и false для CART_SUCCESS. Таким образом, вы сможете сделать банальный if в шаблоне рендера и показывать либо разметку прелоадера, либо разметук с данными корзины.

    === вторая часть ===
    В компонентах-контроллерах есть только функция connect() со своими функциями-аргументами, которые передают данные в представление. Как-то реагировать на изменения состояния такие компоненты не умеют (я ведь не ошибаюсь в этом?).

    Еще как умеют, в этом и суть. Вы в mapStateToProps передаете в общем случае:
    {
      ваше_название_поля: reduxStore.название_редьюсера
    }

    В частном случае, может выглядеть так:
    function mapStateToProps(state) {
      return {
        rate: state.rate,
      }
    }


    После того, как вы "подписались" на изменения в state.rate, (а это, если говорить об частном случае, скорее всего reducer с названием rate), ваш "приконекченный" компонент всегда будет получать новые props при изменении в редьюсере. Следовательно, будет вызываться функция render. Само собой - можно хоть сколько "редьюсеров подключить" к одному компоненту.

    Имейте ввиду, что все здесь написано для понимания простым русским языком, на самом деле, так как вы используете компонент Provider на самом верхнем уровне вашего приложения, он прокидывает необходимые props вниз. Ваши connect(Компоненты) умеют реагировать на изменение необходимых props => реакт вызывает рендер, так как "пришли новые props".
    Ответ написан
    2 комментария
  • Как сделать анимацию добавления элемента?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Есть анимация в реакте ( React transition group ), которая сделана на основе ng-animate, которая в свою очередь использовалась в ангуляре. Если с ней знакомы, то быстро въедете, если нет - придется, наверное, пару раз перечитать доку.

    Суть: вы добавляете css классы по типу NAME-enter, NAME-enter-active и подобное (все опять же есть по ссылке выше), а в реакт компоненте указываете внутри ReactCSSTransitionGroup transitionName="NAME"
    Ответ написан
    Комментировать
  • Как перерисовывается DOM при использовании с Redux?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    В общем случае, метод render компонента вызывается в случае изменения state / props
    Никто (даже создатель библиотеки Redux) не просит вас отказываться от state. Это хорошая и удобная "фича" компонентов в react.

    Когда вы подключаете redux, вы оборачиваете все свое приложение в Provider (конечно, с указанием store). Затем Provider прокидывает куда нужно (в зависимости от ваших "подключенных" через функцию connect компонентов) необходимые props. Так как приходят новые props - вызывается метод render и компонент перерисовывается.

    Во всем этом можно убедиться, если посмотреть ваше корректное приложение на redux через React Dev Tools в консоли браузера. Вы увидите, что на самом верху "гнездится" Provider с кучей данных. Затем ниже по дереву, вы найдете свои, обернтуые в connect(Компонент) компоненты. Никакой магии здесь нет.
    Ответ написан
    Комментировать
  • Как правильно реализовать сортировку и сортинг в redux для больших объёмов данных?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Поддерживаю, Mikhail Osher по поводу normalizr. По этому поводу хорошо объясняется (на англ) в этом курсе: Building React Applications with Idiomatic Redux.
    Ссылка на урок про normalizr внутри этого курса.
    Ответ написан
    Комментировать
  • Общая библиотека для юнит тестирования React Redux GQL?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Редьюсеры (из мира redux, да и вообще) тестируются очень удобно. Ваш тест в общем виде выглядит так:
    1) есть начальное состояние
    2) есть action с такими-то данными (или без)
    3) есть конечное состояние (заданное вами, вручную, ожидаемое состояние)
    4) вызываю reducer(с action указанным в пункте 2) и сравниваю результат с пунктом 3

    Банальный тест. Проверяем, что устанавливается isFetching в true в момент запроса.
    // кусочек из reducer'a
      case GET_DETAILED_FILES_REQUEST:
          return {
            ...state,
            isFetching: true,
          }
    ...
    
      // код из теста
      it('GET_DETAILED_FILES_REQUEST', () => {
    
          const action = {
            type: GET_DETAILED_FILES_REQUEST,
          }
    
          const nextState = reducer(initialState, action) // где reducer = ваш настоящий редьюсер, например " import reducer from '../../src/reducers/detailedFiles' "
    
          expect(nextState).to.deep.equal({
            ...initialState,
            isFetching: true,
          })
        })


    По тестированию редьюсеров, в документации есть все что нужно, чтобы начать.
    Ответ написан
  • Где хранить текущее значение формы?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    я храню меняющуюся информацию в state именно этого компонента

    Это логично, для этого (изменяемых свойств компонента) и был придуман state.

    стоит ли эти текущие state объявить в state всего приложения и менять их там

    Я так понимаю, под state всего приложения понимается либо redux store, либо state какого-то родительского компонента. Если второе - однозначно нет, так как при изменении - будет перерисовываться всё приложение (все потомки), если же речь идет про redux store, то какие-то данные, которые необходимы вам в других местах (кроме текущего компонента) стоит класть туда, но при этом иметь ввиду, что все компоненты, которые "подписаны на эти данные" (с помощью функции connect) будут перерисовываться при изменении.

    p.s. отвечая на вопрос "где хранить текущее значение формы?" - я бы хранил в state компонента, так как обычно оно больше нигде в других компонентах не нужно.
    Ответ написан
    3 комментария
  • Сколько раз вызывается connetc()?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    В обоих случаях. В начале, так как компонент наверняка где-то подключается, а раз он подключается (например через import MyComp), то весь код выполнится. Так же в случае изменения "примапленных" данных.

    Самый простой способ проверить это - добавить console.log и посмотреть.

    connect( (state)=> {
        console.log('вызван connect')
        return state.arrayValues.filter(val => val.includes(a));//массив со строками
      },
      (dipatch)=>({})
    );
    Ответ написан
    5 комментариев
  • Почему компонент не слушает хранилище?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Предположу 2 ситуации:
    1) Как вам уже сказали в комментариях, скорее всего вы "мутируете" массив, а не возвращаете новый. Например, вам не подходит, метод push, чтобы добавить элемент и вернуть новый массив, используйте concat.

    2) Если вы подключили компонент (с помощью connect), и не прокидываете props вниз потомку, который в свою очередь не прокидывает эти пропс вашему компоненту, который не работает и находится на 3м уровне, не имея прямой связи... то и работать не должно. Чтобы "не прокидывать", можно использовать context, но вряд ли вам это сейчас нужно. Мне, пока что, context использовать напрямую не приходилось.
    Ответ написан
    1 комментарий
  • React + Redux. Какую библиотеку или компонент выбрать для локализации?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Частично ваши запросы может удовлетворить react-intl
    Статья от нашего коллеги (на англ) - там стоит поизучать комментарии. А вот и сам автор на хабре.

    В данный момент тоже пользуюсь react-intl для перевода, но из функционала использую только перевод констант.
    Ответ написан
    Комментировать
  • Как настроить динамический роутинг дочерних компонентов в react-router?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Не вижу проблемы..
    <Route path={"/rooms/:chatroomId"} component={ChatBox} />

    В коде Rooms - стандартно - this.props.children, так как ChatBox является потомком...

    p.s. или вы что-то иное хотели спросить?
    Ответ написан
    3 комментария