Рубрики
Без рубрики

Реализовать многоразовую редуктор логику

Шаг за шагом подход к реализации многоразовой редуктовой логики в вашем реагированном проекте

Автор оригинала: Sunday Nwuguru.

Я встретил Mentee, который работал над проектом, который потребовал его отображения двух музыкальных плейлистов разного жанра на той же странице. Он не хотел писать два отдельных редуктора для этого компонента, так как единственное различие было идентификатор плейлиста. Он добрался до меня, но я не смог помочь ему. У меня никогда не было никаких причин создавать многоразовый редуктор. Хотя доступен доход к Восстановление редуктора логических примеров Документ, он все еще не смог осуществить эти примеры в его проекте. Я решил написать это руководство, чтобы помочь другим людям с той же нужностью.

В этом руководстве я поделился двумя реализациями Восстановление редуктора логических примеров с тобой. Я поделюсь с ними в пошаговом подходе о том, как интегрировать это с помощью вашего Реагировать проект. Первая реализация будет иметь один ключ в магазине с несколькими ветвями, когда второй будет иметь несколько клавиш в магазине, используя одну и ту же логику редуктора.

  // First implementation store structure
 {
  posts:{
    a_posts:{ items:[], isFetching: false},
    b_posts:{ items:[], isFetching: false}
    ...
  }
 }
 
 // Second implementation store structure
 {
  a_posts:{ items:[], isFetching: false},
  b_posts:{ items:[], isFetching: false}
  ...
 }

Аудитория

Это руководство предполагает, что вы знакомы с концепцией Redux. Если это не так для вас, прочитайте это Введение в redux и Начало работы с React Redux: Intro Во-первых, затем верните здесь, чтобы узнать, как реализовать многоразовую логику редуктора.

Что мы строим

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

Конфигурация окружающей среды

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

Бег клонированного репо

Если вы клонировали репо Откройте свой терминал и перейдите к каталогу проекта. Установите зависимости и запустите сервер. Следуйте инструкциям ниже:

  • CD React - Redux-Reasable-редуктор
  • Установка NPM
  • Начнем NPM

Проект будет компилировать, начать сервер разработки на http://localhost: 3000/ И откройте свой браузер, указывающий на этот адрес. Вы можете проверить V2 ветвь, чтобы увидеть вторую реализацию.

Скелет проекта

Чтобы начать работу, нам нужно инициализировать скелет React Project с использованием Create-React-App модуль. Если у вас еще нет Create-React-App просто беги NPM Установить -G Create-React-App В вашем терминале установить его по всему миру. Далее нам нужно генерировать нашу колючевую таблицу App App. Запустите следующее в своем терминале:

  create-react-app react-redux-reusable-reducer
  cd react-redux-reusable-reducer/
  npm start

Открыть http://localhost: 3000 Чтобы увидеть ваш начальный проектный скелет.

Установка зависимостей

Нам нужно установить некоторые проектные зависимости. Не стесняйтесь вынуть изоморфно-выборки Если вы не звоните внешним API с помощью извлекать Отказ В противном случае запустите следующее в своем терминале:

npm install react-redux redux-thunk isomorphic-fetch --save

Действия

Мы начнем с действий для нашего приложения блога. Посмотрите на Действия Объяснение Если вы еще не знаете, какие действия есть.

Под SRC каталог, создать другой каталог под названием Сообщения Отказ Внутри Сообщения каталог, создать Actions.js Файл со следующим контентом:

SRC/Actions.js.

  // import fetch from 'isomorphic-fetch';

  export const REQUEST_POSTS = "FETCH_POSTS";
  export const RECEIVE_POSTS = "RECEIVE_POSTS";

  let sampleResponse = [
    {"title":"test title 1","id":1976235410884491574,"category":"a"},
    {"title":"test title 2","id":3510942875414458836,"category":"a"},
    {"title":"test title 3","id":6263450610539110790,"category":"b"},
    {"title":"test title 4","id":2015796113853353331,"category":"b"}
  ]

  export function requestPosts(name) {
    return {
      type: REQUEST_POSTS,
      name
    }
  }

  export function receivePosts(payload, name) {
    return {
      type: RECEIVE_POSTS,
      name,
      items: payload
    }
  }

  export function fetchPosts(query, name) {

    return dispatch => {
      dispatch(requestPosts(name))
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          let result = sampleResponse.filter(function(item){
            return item.category === query.cat
          })
          resolve(result);
        }, 1000);
      }).then(payload => dispatch(receivePosts(payload, name)));

      /*
      // You can use this to call an external api endpoint
      return fetch("http://example.com/api?cat=" + query.cat)
        .then(function(response){
           return response.json()
        })
        .then(payload => dispatch(receivePosts(payload, name)))
        */
    }
  }

Если вы изучите код выше, вы заметите, что все действия имеют Имя Параметр – это будет использоваться для отслеживания компонента, который отправляет действие.

Примечание: Вам не нужно вызывать этот параметр Имя ; Вы можете назвать это, все, что вы хотите.

Редукторы

Пришло время написать логику редуктора, которая обрабатывает, как состояние заявки изменяется в ответ на действия пользователей. Читайте о Редукторы Если вам интересно, что они есть и как они работают.

Внутри Сообщения каталог, создать файл под названием Редукторы.js со следующим содержанием:

SRC/редукторы.js (внедрение V1)

  import {
    REQUEST_POSTS, RECEIVE_POSTS
  } from './actions'

  let singleState = {items: [], isFetching: false};
  let initialState = {
    a_posts : singleState,
    b_posts : singleState,
  }

  export function posts(state = initialState, action) {
    let data = initialState;
    switch (action.type) {
      case REQUEST_POSTS:
        data[action.name].isFetching = true;
        return Object.assign({}, state, data)
      case RECEIVE_POSTS:
        data[action.name].items =  action.items
        data[action.name].isFetching = false;
        return Object.assign({}, state, data)
      default:
        return state
    }
  }

В редукторной логике выше начальное состояние каждого компонента будет храниться в своем ключе.

  let initialState = {
      a_posts : singleState,
      b_posts : singleState,
      c_posts : singleState,
      ...
    }

Вы можете решить добавить больше к нему, как показано выше. Кроме того, обратите внимание, что ключевое имя – это то же имя, которое мы отправили в действия. Новое состояние вычисляется и возвращено в соответствующий ключ на основе имени, отправленного действиями.

Теперь давайте посмотрим на вторую реализацию.

SRC/Reeders.js (внедрение V2)

  import {
    REQUEST_POSTS, RECEIVE_POSTS
  } from './actions'

  let initialState = {items: [], isFetching: false};

  export function postWithName(name) {
    return function posts(state = initialState, action) {
      if(name !== action.name)
        return state;

      switch (action.type) {
        case REQUEST_POSTS:
          return Object.assign({}, state, {isFetching: true})
        case RECEIVE_POSTS:
          return Object.assign({}, state, {isFetching: false, items: action.items})
        default:
          return state
      }
    }
  }

Post WithName Функция возвращает внутреннюю функцию (фактическая логика редуктора) и Имя Параметр используется для сравнения имени в действии, отправленном. Если имя не равно, текущее состояние возвращено. Смотрите другие реализации здесь Отказ

Магазин

Магазин содержит все состояние приложения. Узнай больше о магазине здесь Если вы еще не знаете.

Мы реализуем логику магазина в файле ввода index.js Отказ Откройте свой нынешний index.js и заменить его следующим кодом:

SRC/index.js (внедрение V1)

  import React from 'react';
  import thunkMiddleware from 'redux-thunk';
  import { render } from 'react-dom';
  import { Provider } from 'react-redux';
  import { createStore, applyMiddleware } from 'redux';
  import { posts } from './posts/reducers';
  import App from './App';


  function storeWrapper(state = {}, action) {
    return {
      posts: posts(state.posts, action)
    }
  }

  let store = createStore(
    storeWrapper,
    applyMiddleware(
        thunkMiddleware
      )
    )

  render(
    
      
    ,
    document.getElementById('root')
  )

Здесь ничего особенного, только один ключ Сообщения Отказ Это будет держать другие ключи, как указано в логике редуктора, каждый ключ с его собственным состоянием. Давайте посмотрим на реализацию V2.

SRC/index.js (внедрение V2)

  import React from 'react';
  import thunkMiddleware from 'redux-thunk';
  import { render } from 'react-dom';
  import { Provider } from 'react-redux';
  import { createStore, applyMiddleware } from 'redux';
  import { postWithName } from './posts/reducers';
  import App from './App';


  function storeWrapper(state = {}, action) {
    return {
      a_posts: postWithName('a_posts')(state.a_posts, action),
      b_posts: postWithName('b_posts')(state.a_posts, action)
    }
  }

  let store = createStore(
    storeWrapper,
    applyMiddleware(
        thunkMiddleware
      )
    )

  render(
    
      
    ,
    document.getElementById('root')
  )

Единственная разница здесь в StoreWrapper функция. Post WithName Функция вернет фактическую логику редуктора. Я думаю, вы, вероятно, выяснили, почему мы использовали двойной скобки 😉

return {
    a_posts: postWithName('a_posts')(state.a_posts, action),
    b_posts: postWithName('b_posts')(state.a_posts, action)
  }

Первые скобки называют Post WithName Функция с именем для компонента, который сможет изменять состояние, а вторая скобка вызывает возвращенную логику редуктора с текущим состоянием и действием.

Примечание: Это не обязательно, что название ключей будет то же самое имя для Post WithName функция.

Отображать компоненты

Мы закончили с тяжелой частью. Давайте создадим компонент, который будет отображать сообщения. Создайте каталог по адресу поста, которые мы создали ранее – этот новый каталог будет называться Компоненты Отказ Вставьте следующий код в файл под названием posts.js в недавно созданном каталоге.

SRC/посты/компоненты/post.js

  import React, { PropTypes, Component } from 'react'

  export default class Posts extends Component {
    render() {
      return (
        
    {this.props.posts.map((post, i) =>
  • {post.title} ({post.category})
  • )}
) } } Posts.propTypes = { posts: PropTypes.array.isRequired }

Дисплей контейнер

Контейнер будет служить источником данных для нашего компонента отображения. Эта статья объясняет это хорошо. Создайте другой каталог Контейнеры Внутренний каталог постов и добавьте следующий код в Postlist.js Отказ

SRC/посты/контейнеры/PostList.js (внедрение V1)

  import React, { Component, PropTypes } from 'react'
  import { connect } from 'react-redux'
  import { fetchPosts } from '../actions'
  import Posts from '../components/posts'

  class PostContainer extends Component {

    componentDidMount() {
      const { dispatch} = this.props
      dispatch(fetchPosts({cat:this.props.cat}, this.props.name))
    }

    render() {
      const { posts, isFetching } = this.props
      return (

        
{isFetching &&
Loading...
} {posts.length > 0 &&
}
) } } PostContainer.propTypes = { posts: PropTypes.array.isRequired, cat: PropTypes.string.isRequired, isFetching: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, dispatch: PropTypes.func.isRequired } function mapStateToProps(state, props) { return { posts: state.posts[props.name].items, isFetching: state.posts[props.name].isFetching, } } export default connect(mapStateToProps)(PostContainer)

SRC/посты/контейнеры/PostList.js (внедрение V2)

  import React, { Component, PropTypes } from 'react'
  import { connect } from 'react-redux'
  import { fetchPosts } from '../actions'
  import Posts from '../components/posts'

  class PostContainer extends Component {

    componentDidMount() {
      const { dispatch} = this.props
      dispatch(fetchPosts({cat:this.props.cat}, this.props.name))
    }

    render() {
      const { posts, isFetching } = this.props
      return (

        
{isFetching &&
Loading...
} {posts.length > 0 &&
}
) } } PostContainer.propTypes = { posts: PropTypes.array.isRequired, cat: PropTypes.string.isRequired, isFetching: PropTypes.bool.isRequired, name: PropTypes.string.isRequired, dispatch: PropTypes.func.isRequired } function mapStateToProps(state, props) { return { posts: state[props.name].items, isFetching: state[props.name].isFetching, } } export default connect(mapStateToProps)(PostContainer)

Разница в двух версиях кода выше является MapstatetoProps Функции. Если вы посмотрите на возвращенный объект, вы заметите, что первая реализация получает значения из State.posts [ropps.name] Пока второй получает значение из состояние [ropps.name] Отказ

Заключительный этап

Пришло время подключить финальную часть нашего блогов приложения постов и, наконец, проверить результат. В корневой папке замените App.js Содержимое со следующим кодом:

src/app.js.

  import React from 'react'
  import PostList from './posts/containers/PostList'

  const App = () => (
    

Posts - Category A

Posts - Category B

) export default App

В коде выше, Пособие используется дважды с двумя реквизитами кот и Имя Отказ кот Стоимость использования в фильтрации входящих постов в то время как Имя используется для идентификации компонента отправленных действий.

Если у вас все еще есть свой сервер работает, вы должны увидеть результат в вашем браузере. Вы можете запустить NPM начать В вашем терминале из корневой папки проекта, если ваш сервер не работает.

Результат скриншота

Снимок экрана 2017-02-23 в 9.48.59 PM.PNG

Последнее примечание

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