У меня есть канал bit.ly/teletoster на котором я провожу вебинары, публикую интересные материалы.
Так же - группа vk - https://vk.com/maxpfrontend
YouTube канал - bit.ly/youtubechannelmpf

Сайт - https://maxpfrontend.ru

Если вы ищете учебники по реакту на русском языке - загляните сюда:
- https://habr.com/ru/post/418581/ (react)
- https://habr.com/ru/post/420979/ (redux)

Консультирую - https://maxpfrontend.ru/uncategorized/react-redux-...

p.s. играю [в основном] drum & bass, миксы здесь.


counter.php?maxfarseer border="0" alt="Web Counters">
Контакты

Достижения

Все достижения (33)

Наибольший вклад в теги

Все теги (93)

Лучшие ответы пользователя

Все ответы (550)
  • Какой необходимый уровень знаний для 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.js?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Курс по react.js на русском языке в формате текста.
    Ответ написан
    Комментировать
  • Node js: Error: Can't set headers after they are sent что произошло?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Ошибка говорит о том, что у вас express пытается ответить с заголовком (в стиле "Статус 200" - все ок).
    Проблема в том, что у вас уже был ответ, и еще раз ответить он не может. Дословно: не могу установить заголовки, после того, как они отправлены.

    Решение, всегда использовать ключевое слово return, когда вы "отвечаете". В вашем примере это либо res.json, либо next. Суть в этом.
    Пример из api:
    d4b2dd2981684414a39e31573f403b77.jpg
    Если убрать return, то в случае ошибки, мы попадем в if (err) ..., ответим как ошибка(400), и не выйдем из роутинг функции, пойдем ниже и ответим как успешно(200) - и бам-с, получим ошибку - не могу установить заголовки...
    Ответ написан
    2 комментария
  • Модульность на фронтенде?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    (кратко про себя)
    Все лежит в папках: компонент + стиль. Собирается webpack'ом. Но у меня react-проекты.

    (длинно, но вроде бы по делу)
    Если относительно долго занимаетесь - у вас скорее всего уже выработались части, которые похожи - их выносите. Так же скорее всего у вас есть одинаковая структура (обычно это js/css/images и html, либо как вы пишите компонентами (отдельными папками) внутри котороых html + стили и может js ). Делайте шаблон для будущих проектов, в первую очередь удобным для себя - ведь вам с ним работать, а в нем реализуйте то что умеете по-максимуму (жмите картинки, оптимизируйте js и т.д)

    Плагины, которые используете для Gulp, просто проверьте в блэклисте, а так же можете посмотреть новые версии. Вообще, хорошо если вы знаете все свои плагины, в таком случае - вам и этот пункт можно не выполнять.

    кажется, что не использовал это все на 100%

    Всем так кажется, поэтому когда не хочется заниматься работой, идем в гугл и смотрим опен-сорс проекты других людей: gulp, wepback, затем если нашли что-то любопытное идем в npm/github читаем доку. Пытаемся применить в работе.

    Что имеем в итоге?
    1) если все работает и вас устраивает (скорость сборки, удобство проверки в разных браузерах ...) - "работу работать";
    2) если есть время и желание - гуглите опен-сорс решения, читайте твиттер интересных людей / новостную подписку;
    3) если хочется услышать мнение коллег, но при этом коллег рядом нет - пишите статью на хабр. Просто статья: я использую такие-то плагины в своем "шаблоне" - вряд ли получит лестные отзывы, но возможно кто-то напишет: вот в этом месте у вас плохо, сделайте иначе. Возможно, вы придумаете, как написать статью интересно - тогда честь и хвала. И критика. А обоснованная критика всегда хорошо.

    P.S. если используете Jade и следуете BEM-методологии, то я бы порекомендовал посмотреть на этот проект
    Ответ написан
    Комментировать
  • Как реализовать авторизацию пользователя на стеке 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 комментариев

Лучшие вопросы пользователя

Все вопросы (8)