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

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

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

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

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

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    В тему про codementor.io (ссылка, почему-то неправильно вставляется)
    https://www.codementor.io/experts?q=nodejs&lang=russian
    Ответ написан
    Комментировать
  • Библиотека асинхронных запросов для react?

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

    Есть проект, на бэкэнде elixir+phoenix. Мне в каждом сообщении приходит ref + автоинкреметный id. Следовательно, когда я делаю первый запрос и данные идут долго, а потом второй запрос и данные приходят быстрее, то ref будет больше и я просто в редьюсере игнорирую старый ответ (в стиле, action.ref < state.ref => верни текущий стэйт).

    P.S. если используете сокеты, как вы "замедляете" получение ответа? Мне пришлось попросить "бэкэнд" отвечать медленнее, для тестирования этой проблемы. Так как в chrome devtools в нетворке "замедление" не работало для запросов по сокету.
    Ответ написан
    Комментировать
  • Как динамически добавить компонент в React?

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

    (перевел главный кусок с ответа по ссылке выше)

    // ...
    // SampleComponent - ваш однотипный компонент
    // ...
    
    class Test extends Component {
        constructor(props) {
            super(props)
            this.addChild = this.addChild.bind(this)
            this.state = {
                components: [
                    {
                        id:1, name: 'Some Name'
                    }
                ]
            }
        }
    
        addChild() {
            // Изменение стейта спровоцирует перерисовку
            this.setState(this.state.concat([
                {id:2,name:"Another Name"}
            ]))
        }
        render() {
            return (
                <div>
                    <h1>App main component! </h1>
                    <button onClick={this.addChild}>Add component</button>
                    { // здесь будет отрисовано необходимое кол-во компонентов
                        this.state.components.map((item) => (
                            <SampleComponent key={item.id} name={item.name}/>
                        ))
                    }
                </div>
            );
        }
    }
    Ответ написан
    Комментировать
  • Нужен совет по react и angular?

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

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

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

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

    p.s. из вопроса, не понял каков уровень js... Что можете сделать на js (+ jquery и плагины?)
    Ответ написан
  • Nodejs/express + ES6 рекомендации?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    По первому пункту, ссылка от Антона в помощь.

    По второму вопросу: вы на node.js будете делать бэкэнд. Который будет являться API сервером, не более. Здесь придется поизучать что такое REST API. Следовательно, если вы будете писать фронтенд на react/redux, то кладете его в другую директорию, там уже свой package.json и т.д., так как ваш фронтенд и бэкэнд - это две разные вещи.
    Ответ написан
    Комментировать
  • Как в ReactJS организовать подключение компонента из другого файла?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Вам нужно собирать бандл с помощью Wepback / Browserify и т.д. Require / import не сработают, даже если указать text/babel.

    Немного с SO:
    stackoverflow.com/a/36698789/1916578 (почему не работает require/import)
    stackoverflow.com/a/20578692/1916578 (на всякий случай, если вы не используете локальный сервер - здесь есть информация об ошибке и что с этими делать) + локальный сервер легко поднять с помощью http-server
    Ответ написан
    Комментировать
  • Установка react/webpack, в чем проблема?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Могу предположить, что возможно проблемы в пути (есть пробел у директории Study projects). Попробуйте провернуть все это в директории, в пути до которой нет пробелов.
    Ответ написан
  • Eslint Best practices?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Во многих статьях вижу конфиг от airbnb, список правил тут

    В .eslintrc есть возможность "унаследовать конфиг". Например,

    {
      "extends": "eslint:recommended", // унаследовали от eslint:recommended
      ...
      "rules": { // переопределили/добавили свои правила
        "no-debugger": 0,
        "no-console": 0,
        ...
      }
    }
    Ответ написан
    Комментировать
  • Сортировка данных в 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.JS сделать поочередный вывод из массива данных JSON?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Вам нужно сделать API, которое будет отдавать определенное кол-во записей. Поясню: вам нужно сделать backend, так сказать. Можно написать на node.js / php / python / и т.д. Возможно, есть какой-то готовый сервис для подобных вещей, но я не искал.

    Например: GET запрос на api/loadjson?limit=100&offset=0 (выдай 100, отступ 0, потом будет запрос выдай 100 - отступ 100, выдай 100 отступ 200 и тд), т.е. в теории дело обстоит так: вы загружаете первые N записей и устанавливаете обработчик на window.onscroll (пример тут), далее выбираете через какой интервал в пикселях вы планируете подгружать еще и загружаете еще N записей и так далее.

    Подгрузку осуществляете с помощью xhr (или, если угодно - ajax) запросов (мне нравится isomorphic-fetch)

    Из готовых компонентов, рекомендую react-virtualized. Настройка сперва выглядит трудновато, но это одна из лучших библиотек в плане документации, которую я видел. Есть все! На всякий случай - gitter чат, где есть и сам разработчик (язык EN).
    Ответ написан
    5 комментариев
  • Как реализовать авторизацию пользователя на стеке 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 комментариев
  • Как использовать jsx?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Emmet поддерживается в JSX (sublime, например)
    Ответ написан
    4 комментария
  • Как создать очередь показа изображений?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Очередь с реактом ничем не отличается от "очереди с чем угодно". Можете использовать requestAnimationFrame (EN, на русском тоже есть в гугле) + "как контролировать fps", или setInterval / setTimeout.

    Реакт тут вообще не причем, когда напишите код для показа без него, добавьте этот код в код компонента и все.
    ---
    Алгортим примерно следующий:
    1) загружаете список url
    2) по нему начинаете загружать картинки (стандартно, с помощьюconst img = new Image + img.onload = ... )
    3) эти картинки складываете в очередь (в массив)
    4) начинаете показывать

    Показ вы начинаете либо в случае загрузки первого кадра и далее по ходу загрузки остальных, либо после загрузки всех - это уж как вам угодно.
    Ответ написан
    Комментировать
  • React+Redux VS Backbone (Marionette) в 2017?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    1. Поясните этот момент. Поиск, фильтрация... это же обычные операции на vanila js? Спокойно обрабатывайте ваши данные в reducer'ах, хоть с помощью underscore, хоть с помощью lo-dash...
    2. Разделение кода возможно. Так как за сборку отвечает обычно webpack, начать можно с небольшого теоретического экскурса здесь: Кантор (ру) (гугл, подкидывает еще (англ.))
    3. Не мало всего уже есть, но конечно меньше.

    Направлять вас на путь истинный вряд ли нужно: у вас есть задачи, решайте их так как умеете и зарабатывайте. Появится время для изучения реакта - успеете подучить.
    Ответ написан
    Комментировать
  • Как найти преподавателя по Node.js?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Как уже писал не раз тут на тостере - начните с codementor.io (поиском node.js и russian). Там ставка выше, но я думаю сможете договориться.

    P.S. в целом же, менторов на русском языке найти очень не просто.
    Ответ написан
  • Как запустить meteor.js?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Можно запускать команду через screen
    То есть, команда screen как будто бы открывает виртуальную вкладку, в ней запускаете meteor, затем выходите из скрина (обычно это ctrl + A,D ) и у вас "сессия" в той виртуальной вкладке остается висеть. Чтобы снова к ней присоединиться, нужно написать screen -R. Ну или просто почитайте подробнее про screen.
    Ответ написан
    1 комментарий
  • Какой использовать стэк для одностраничного медиа веб-приложения?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Поддержу Владимир Ио про "зачем переписывать", но добавлю, что человека на проект написанный на react, найти будет проще чем специлаиста по бэкбону / vue. Про рост числа vue- специалистов не знаю, а вот backbone думаю только убавляет в спецах и тенденция усилится со временем. Реакт же - очень интенсивно набирает все больше "разработчиков" и поэтому с точки зрения поддержки, будет дешевле.

    Я бы сам предпочел react. Ничего не имею против vue / angular (пусть его и нет в вопросе), но с точки зрения дешевизны поддержки, react сейчас дороже angular, но думаю уже дешевле backbone (чисто "диванная" и немного hh.ru аналитика). Со временем (думаю не далее чем вторая половина 2017 года) цена поиска и найма angular/react специалистов будет примерно равна.
    Ответ написан
    Комментировать
  • Как лучше всего реализовать CRUD - DOM на ReactJS?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    по поводу вопроса 2: вам будет необходимо взять еще что-то. Например, можно использовать веб сокеты, чтобы рассылать всем подписчикам события: элемент_создан / удален и т.д. Без такой "рассылки" по подписчикам (подключенным клиентам) не получится сделать, разве что будет какой-то костыль с таймером (не надо так).

    по поводу вопроса 1, за неимением хорошего простого примера под рукой, предлагаю сделать по шагам, если получится - уверяю, с "расширением" пойдет гораздо лучше:

    Например есть страница с номерами телефонов и именем.

    На этой странице у вас компонент PhonesAndNames в момент componentDidMount делаете xhr вызов и получает список всех телефонов и номеров. Например, это GET запрос на ваш сервер: GET /api/phones

    Полученные данные вы кладете в state и в рендере компонента у вас строится таблица по данным из state компонента. Следовательно, как только у вас xhr запрос завершится, данные окажутся в state, случится ре-рендер и все будет хорошо. Для полного счастья, можно добавить переменную isLoading, например, и ставить ей true в начале выполнения запроса, и false в момент получения ответа. В рендере компонента, в зависимости от значения isLoading - рисовать прелоадер. Конечно, isLoading тоже будет жить в state.

    Далее, при наведении на строку - у вас, к примеру рисуется "крестик". По клику на крестик - производится запрос на сервер, например: DELETE /api/phones/айди. Внутри компонента PhonesAndNames это будет просто onClick на элементе крестик и функция, которая опять же отправляет xhr запрос. Когда будет получен ответ, вы должны поиском найти id удаленного элемента из вашего списка в state и вернуть список элементов. Изменился state - случился ререндер - все в порядке.

    Так же с добавлением. Вам достаточно поставить пару input'ов + кнопку "добавить". Опять обработчик на onClick (или на onSubmit, если сделаете это как форму) - опять xhr запрос (POST /api/phones), опять на успешный ответ операция со списком телефонов и имен в state, а именно: банально добавление в конец или в начало нового элемента.

    Остался только update. С ним тоже самое. В простейшем примере, чтобы не заморачиваться, все ваши телефоны и имена могут быть в таблице внутри тэга input и в конце строки, там же где крестик - иконка "обновить".
    ---
    Получается, если вы будете использовать web-сокеты, то вам нужно будет настроить свой сервер так, чтобы в момент успешного ответа на все вышеизложенные методы бродкастилось (от broadcast, т.е. рассылать) какое-то событие, на которое ваши клиенты умеют реагировать.
    ---

    Чтобы все это в процессе "расширения" и "усложнения" не превратилось в трудноподдерживаемую кашу, рекомендую использовать любую из библиотек для "управления состоянияем приложения", так сказать. Мне очень нравится redux.
    Ответ написан
    7 комментариев
  • Стоит ли использовать 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 комментария