Ответы пользователя по тегу Redux
  • Почему store undefined?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Вам прежде всего стоит с основами JavaScript разобраться, и только когда будут уверенные знания браться за React.

    1. Вы передаете в компонент свойство data, но нигде не используете.
    2. Объявляете состояние в редьюсере как массив, затем подменяете на объект.
    3. Сами хоть поняли что имели ввиду в этой строчке:
    if (posts && posts == 'undefained') {
    4. В этой строчке так же ошибка:
    let posts = this.props
    вероятно правильный вариант такой:
    const { data } = this.props;
    Ответ написан
    8 комментариев
  • Правильно я визуализировал работу под капотом в Redux+ReactRedux после Reducer?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Все происходит совсем не так. Вы, видимо, пытаетесь угадать, а достаточно лишь изучить исходный код библиотеки react-redux и почитать про метод store.subscribe redux.

    redux и react-redux это две ничем не связанные и не подозревающие о существовании друг друга библиотеки. Компоненты react-redux лишь используют API объекта store из redux, который вы должны передать в Provider сами.
    Когда вы подключаете react-redux вы используете компонент Provider и HOC connect. Ниже перечислены их основные функции.

    Provider:
    1. Получает в props store и подписывается на его обновления с помощью store.subscribe.
    2. Инициирует перерисовку дочернего древа по обновлению store, с помощью вызова this.setState.
    3. Передает в контекст store и storeState(результат вызова store.getState())

    HOC connect:
    1. Передает нужные props в оборачиваемый компонент с помощью, полученного через контекст, состояния и маппера mapStateToProps.
    2. Оборачивает actions в вызов store.dispatch с помощью store, полученного через контекст, и маппера mapDispatchToProps, либо просто передает store.dispatch в props компонента как свойство dispatch.
    3. Если аргумент mapStateToProps был передан, то компонент-обертка, возвращенный вызовом connect, отслеживает обновления store. Если свойства полученные из store и props не были изменены, а компонент уже отрисован, то connect при обновлении возвращает сохраненный по ссылке отрисованный компонент, если изменения были, то дочерний компонент перерисовывается. Логику обновления можно понять, взглянув на функцию, результат вызова которой, вызывается в render компонента обертки:
    function makeChildElementSelector() {
      let lastChildProps, lastForwardRef, lastChildElement
    
      return function selectChildElement(childProps, forwardRef) {
        if (childProps !== lastChildProps || forwardRef !== lastForwardRef) {
          lastChildProps = childProps
          lastForwardRef = forwardRef
          lastChildElement = (
            <FinalWrappedComponent {...childProps} ref={forwardRef} />
          )
        }
    
        return lastChildElement
      }
    }


    Подробнее: react-redux with Dan Abramov
    Ответ написан
    Комментировать
  • Как правильно сделать import обычного класса в React компонент?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Ошибка линтера no-unused-expressions. Импортируете модуль, но не используете.

    Учитесь читать и понимать тексты ошибок, а так же самостоятельно гуглить решения проблем. Для этого достаточно вбить в поисковике текст ошибки.
    Ответ написан
    4 комментария
  • Почему не наследуются props через redux метод connect в в компонент App?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    /* ... */
    
    const mapStateToProps = state => ({
      desks: state.desks,
    });
    
    const ConnectedApp = ReactRedux.connect(mapStateToProps)(App);
    
    ReactDOM.render(
      <ReactRedux.Provider store={store}>
        <ConnectedApp />
      </ReactRedux.Provider>, 
      document.querySelector('#root'),
    );
    Ответ написан
    Комментировать
  • Context API можно использовать вместе Redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Context API можно использовать вместе Redux?

    Можно и нужно.

    И по нажатию на одну из этих кнопок, у меня должна выскакивать модалка с формой.

    Глобальные модалки лучше через Redux.

    Если данный кейс не корректен, то можете привести примеры когда целесообразнее использовать Context API, чем пихать инфу в Redux?

    Темы, локали, UA все это удобней использовать с Context API
    Ответ написан
    2 комментария
  • React + Redux, как записать в состояние после того как придут данные?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    static getDerivedStateFromProps(props, state) {
      if (props.visas[0] !== state.visa) {
        return {
          visa: props.visas[0],
        };
      }
    
      return null;
    }

    Массив this.props.visa должен существовать всегда.
    Ответ написан
    Комментировать
  • Является ли хорошей практикой использовать setState в redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    По-хорошему в redux выносят только то, что используется в разных частях приложения, а так же данные полученные с сервера. Для остального предпочтительней использовать state компонента. В подавляющем большинстве случаев, lifting state up будет предпочтительней использования redux.

    Ответ Дэна Абрабомова на похожий вопрос How to choose between Redux's store and React's state.
    Ответ написан
    2 комментария
  • Как правильно использовать mapStateToProps с асинхронным поведением компонента?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Не надо обрабатывать подобные вещи в mapStateToProps. Оставьте просто:
    const mapStateToProps = (state, ownProps) => ({
      coin: coinSelector(state, ownProps),
      isLoading: isCoinsLoadingSelector(state),
    });

    В методе render:
    render() {
      const { coin, isLoading } = this.props;
    
      if (isLoading) return <Preloader />;
    
      if (!isLoading && !coin) return <NotFound />;
    
      return <CoinDetails coin={coin} />;
    }

    Учитесь проектировать хранилище, задавать начальное состояние и писать render метод так, чтобы он успешно выполнялся вне зависимости от того получили вы необходимые данные или нет.
    Ответ написан
    4 комментария
  • Возможно ли получить элемент массива из состояния redux, используя mapStateToProps?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    const coinSelector = (state, ownProps) =>
      state.coins.data.find(coin => coin.symbol === ownProps.match.params.id);
    
    const mapStateToProps = (state, ownProps) => ({
      coin: coinSelector(state, ownProps),
    });
    Ответ написан
    Комментировать
  • Disable кнопки после обновления redux store?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Очевидно, что так:
    render() {
        return (
          <SubList d={visibility}>
            {list.map((item, i) => (
              <Button
                key={i.toString()}
                onClick={this.handleClick}
                disabled={item.isLoading}
              />
            ))}
          </SubList>
        );
      }
    Ответ написан
  • Оценка своего уровня. Как улучшить код?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Используйте const вместо let для определения переменных которые не переопределяются в коде. Это помогает снизить когнитивную нагрузку с человека читающего код и негласный стандарт в React разработке.

    2. Такие вещи как globalStyles и конфигурацию store лучше вынести в отдельные файлы. Они могут со временем хорошо разрастись.
    По поводу globalStyles, вы вообще можете вынести их в отдельный css файл.

    3. Вместо:
    {
      isModal
      ? <Route path="/auth" component={AuthPopup} />
      : null
    }

    лучше:
    {isModal && <Route path="/auth" component={AuthPopup} />}


    4. Вместо:
    function mapDispatchToProps(dispatch) {
        return {
            autoLogin: () => dispatch(autoLogin()),
            getBrowser: () => dispatch(getBrowser()),
            getMedia: () => dispatch(getMedia())
        }
    }


    лучше:
    const mapDispatchToProps = {
      autoLogin,
      getBrowser,
      getMedia,
    };


    5. Точки с запятыми в конце то есть, то нет. Определитесь и приведите код к одному виду.

    6.
    & label {}
    & input {}
    & span {}

    Это не очень хороший подход. Во-первых ваши стили не изолированные, что может приводить к неожиданным результатам. Во-вторых у вас очень много дублирования стилей. Определите Input и Label как базовые компоненты и используйте в разных местах, то же с остальным если есть.

    7. Почему папка со страницами называется Containers? Дань бойлерплейтам?

    8. Использование trailing comma является хорошей практикой.

    9.
    import {combineReducers} from 'redux';
    import photoReducer from './photoReducer';
    import authReducer from './authReducer';
    import globalReducer from './globalReducer';
    
    export default combineReducers({
        photoReducer, authReducer, globalReducer
    })


    Все таки приятней работать с хранилищем в котором ключи не имеют в названии слова reducer:
    import {combineReducers} from 'redux';
    import photo from './photoReducer';
    import auth from './authReducer';
    import global from './globalReducer';
    
    export default combineReducers({
      photo, 
      auth,
      global,
    });


    10. Забудьте вообще, что в языке есть возможность использовать вложенный тернарный оператор:
    return e === 'invalid-email' ? 'Неверно указан e-mail'
        : e === 'user-not-found' ? 'Указанный e-mail на найден'
        : e === 'wrong-password' ? 'Неверный пароль'
        : e === 'email-already-in-use' ? 'Указанный e-mail уже используется'
        : e === 'network-request-failed' ? 'Нет подключения к интернету'
        : e === 'operation-not-allowed' ? 'Произошла ошибка, попробуйте снова'
        : e === 'popup-closed-by-user' ? 'Окно авторизации закрыто пользователем'
        : e === 'account-exists-with-different-credential' ? 'Аккаунт уже существует с другими данными, используйте другой способ авторизации'
        : e

    Это одна из самых худших практик в JavaScript разработке. Тут лучше подойдет конструкция switch case

    11. Константы actionTypes лучше вынести в папку constants и разложить по разным файлам, иначе со временем у вас там будет свалка.

    12. Вместо:
    import {SET_ACTIVE, CHANGE_VALUE, SET_DEFAULT, UPLOAD, UPDATE_IMAGE, SET_IMAGE_ERROR, SET_LIKE, SET_COMMENT, ADD_ARTICLE_SUCCESS, FETCH_ARTICLES_START, FETCH_ARTICLES_SUCCESS, FETCH_ARTICLES_ERROR} from '../actions/actionTypes';

    Лучше:
    import {
      SET_ACTIVE,
      CHANGE_VALUE,
      SET_DEFAULT, UPLOAD,  
      UPDATE_IMAGE,
      SET_IMAGE_ERROR,
      SET_LIKE,
      SET_COMMENT,
      ADD_ARTICLE_SUCCESS,
      FETCH_ARTICLES_START,
      FETCH_ARTICLES_SUCCESS,
      FETCH_ARTICLES_ERROR,
    } from '../actions/actionTypes';


    13. Попробуйте внедрить библиотеку reselect. И для получения значения из store вместо записи вида:
    function mapStateToProps(state) {
        return {
            browser: state.globalReducer.browser
        }
    }


    использовать селектор:
    const mapStateToProps = state => ({
      browser: browserSelector(state),
    });
    Ответ написан
    12 комментариев
  • Ререндер - это нормально?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Перерисовка срабатывает только потому, что срабатывает перерисовка родительского компонента. Если родитель React.Component, то его перерисовки можно контролировать с помощью метода shouldComponentUpdate.
    Ответ написан
    Комментировать
  • TypeScript с React + Redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Знаете ли вы статьи и т.д где показано, как на самом деле нужно писать React c TypeScript'ом ?

    Есть две разные технологии. Есть опыт из совместного использования. В статьях которые вы прочитали, а так же в докладах и открытых репозиториях люди делятся своим опытом. О том "как на самом деле нужно" разные люди тут вам скажут немного разное.

    Официальные ссылки:
    TypeScript: React & Webpack
    TypeScript-React-Starter
    Ответ написан
  • Проекты для разбора новичку, для обучения, есть годные?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Открываем github в поиске вводим:
    1. React redux real world
    2. React redux weather app
    3. React redux reddit/twitter/youtube/etc client
    4. React redux dashboard
    5. React redux starter. Бойлерплейты тоже очень полезно изучать. Скачиваем. Открываем package.json изучаем каждый пакет в зависимостях. Отвечаем на вопросы: Что это? Зачем оно тут? Как используется? Необходимо ли оно вам? Если не, то выпиливаем без следа.

    По всем пунктам смотрим именно те проекты, у которых есть какое-никакое количество звезд и форков.

    Читаем все свежие статьи по теме.

    React Redux links
    Ответ написан
    1 комментарий
  • Как правильно использовать react-router и redux в одностраничном приложении?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    game_1 store:
    {
      a: {},
      b: {},
      c: {},
    }


    game_2 store:
    {
      a: {},
      b: {},
      c: {},
    }


    shared store:
    {
      game_1: {
        a: {},
        b: {},
        c: {},
      },
      game_2: {
        a: {},
        b: {},
        c: {},
      },
    }
    Ответ написан
    4 комментария
  • Как порешать ситуацию с дубликатами?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Считать totalPrice и хранить в редьюсере - плохое решение. Изменять сумму на основе предыдущего значения - решение еще хуже. Напишите селектор, который будет считать totalPrice на основе cart.items или считайте сумму каждый рендер.
    2. Не позволяйте добавлять дубликат товара. Вместо этого увеличивайте количество.
    Ответ написан
  • Как практиковать react, redux, router?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Очевидно, что с любого приложения использующего роутинг на стороне клиента:
    1. Классика: Тodo List
    2. Простенький клиент для github
    3. Простенький клиент для reddit
    4. Простенький клиент для twitter
    5. Погодное приложение
    6. Небольшой дашбоард
    7. Витрина онлайн магазина
    8. Поиск авиабилетов, гостиниц и подобного
    и тд

    Вариантов очень много.
    Ответ написан
    2 комментария
  • Как запретить Jest'y проходить по import'ам??

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    ы в файле User импортируете formatTime из индексного файла. Так делать не надо. Тут для легкого тестирования либо props передавать, либо DI для тестирования, либо просто импортируйте не с индексного файла.
    Замените:
    import { formatTime } from "../../../utils";
    на:
    import { formatTime } from "../../../utils/chatFormatTime";


    А все, что связанно с formatTime из файла теста удалите. Ну и моки props для user нужны.

    И еще избегайте циклических зависимостей. В папку utils не должен попадать код из других директорий, только из node_modules и конфигурационных файлов. Если у вас через конфиг в utils попадает store с вашим кодом, что-то не так.
    Ответ написан
  • Почему render выполняеться перед componentWillMount?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Потому что библиотека не ожидает возвращаемое значение в componentWillMount и следом сразу вызывает render.
    Забудьте этот метод - он не рекомендован к использованию. Как уже писали выше, асинхронные запросы рекомендуется инициировать в componentDidMount. Он выполняется после вызова render, который вы по какой-то неясной причине хотите избежать.

    Вот два варианта решения:
    1. До загрузки данных возвращать в render null или прелоадер.
    render() {
       const { data } = this.props;
    
       if (!data) return null;
         
        return (
          <div>
            <FilterModels />
          </div>
        )
      }
    }

    2. Переместить загрузку данных в родительский компонент и отрисовывать целевой по условию:
    render() {
      const { filterData } = this.props;
      return (
        <Wrapper>
          {filterData  && <FilterForm data={filterData} />}
       </Wrapper>
      )
    }
    Ответ написан
    Комментировать
  • Как правильно организовать общение между компонентами?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Можно сделать так:
    1. Метод оnClick передается из родительского компонента.
    2. state иконки высчитывается по полученным props, но так же меняется по клику, для более комфортного пользовательского опыта.
    3. По возвращению ответа от сервера обновляется вся карточка. Так же, обновляется state иконки в computeDerivedState, мало ли была ошибка и товар не попал в избранное.
    4. В случае ошибки, левом нижнем углу экрана можно показать всплывающее уведомление. Для этого можно написать action и вызывать его в блоке catch асинхронных действий.
    Ответ написан