Картинка для понимания принципа React-Redux

внешний интерфейс GitHub React.js Redux

предисловие

В настоящее время изучаетReact-Native, застрял наReact-ReduxПотребовалось некоторое время и усилия, чтобы немного разобраться в его принципах и потоке данных, и я нарисовал картинку и объяснил ее. Надеюсь, те, кто читает эту статью, самые лучшиеReduxНекоторые понимают, если вы не понимаете, вы можете прочитать статью Руан Ифэн. Некоторые объяснения являются личным пониманием и не очень строгие.Если есть ошибки, пожалуйста, поправьте меня.

схема потока данных

Ниже приведен код из блога Ruan Yifeng с некоторыми изменениями, чтобы соответствоватьReact-Native.

root.js

// 创建一个store全局管理state和操作
const store = createStore(reducer);

// Provider在根组件<App>外面包了一层,App的所有子组件就默认都可以拿到store,通过组件的props传递
export default class Root extends Component {
    render() {
        return (
            <Provider store={store}>
                <App/>
            </Provider>
        )
    }
}
app.js

// view提供UI组件
class Counter extends Component {
  render() {
    // View的状态来自于props,props传递的是store中的state
    const { value, onIncreaseClick } = this.props
    return (
      <div>
        <span>{value}</span>
        <button onClick={onIncreaseClick}>Increase</button>
      </div>
    )
  }
}

// 将UI组件和容器组件连接起来
const App = connect(
 state =>({
    value: state.count   //输入,将store中的state通过props输入
 }),
 dispatch =>({    // 输出,将action作为props绑定到View上,用户操作类型在此分发出去
    onIncreaseClick: () => dispatch(increaseAction.increase())
  })
)(Counter)

export default App
increaseAction.js

// 定义action的类型
export const INCREMENT = 'INCREMENT';

// action 创建函数只是简单的返回一个 action
export function increase(params) {
    return {
        type: INCREMENT,
        data:data
        };
}
counterReducer.js

// 提供一个初始的状态
initState={
 count: 0 
}

// 通过判断Action的类型,返回新的数据改变后的state对象,即使没有任何状态的改变,也要返回一个对象
export default function counter(state = initState, action) {
  const count = state.count
  switch (action.type) {
    case INCREMENT:
      return { count: count + 1 }
    default:
      return state
  }
}

Поток данных можно увидеть на рисунке ниже, сначала сViewВ качестве примера, о котором я расскажу позже, эта картина понимает,React-ReduxЭто почти понятно.

Давайте вернемся к первоисточнику и посмотрим на эту картинку по крупицам. Ответьте на вопросы вопросами:

1. В этом примереViewКомпоненты предоставляют только пользовательский интерфейс, а не свой собственныйstateи операций, так что же послужило причиной изменения интерфейса?

даViewсебяprops, мы знаем, что начальное состояние компонента даетсяpropsрешение, хотя и без моего собственногоstate, если егоpropsИзменения происходят, и интерфейс тоже меняется.

2,ViewизpropsЧто обеспечивает содержание, несколькоViewсерединаpropsКак отличить?

глобально уникальный в приложенииstoreсерединаstateПри условии, что все состояние хранится в объекте, отличающемся ключом.<Provider store={store}> <App/> </Provider>Эта строка кода реализует привязку, уникальную для приложения.store.

3.storeКак это произошло?

пройти черезstore = createStore(reducer)Создайте,reducerВозвращается именно измененный объект состояния.

Первые три вопроса объясняют поток данных в левой половине рисунка выше.reducer——(store/state)——provider——(state/props)——view

4.actionкак сreducerсвязанный, илиreducer(state,action)Откуда происходит действие в этой функции?

даstore.dispatch(action)Внутренняя обработка, посмотрите сначалаcreateStore(reducer)Эта функция, сокращенный код выглядит следующим образом:

function createStore = ( reducer ) => {
  let currentState; // 内部的状态
  let listeners = []; //所有的监听者
  
  const getState = () => currentState;  // 获取store中的state
  
  // dispatch的操作就是内部执行reducer()函数,action和reducer在这儿产生交集,并且通知所有的监听者
  const dispatch = ( action ) => {
    currentState = reducer(state, action); // 更新state
    listeners.forEach(listener => listener());
  }
  
  // 订阅事件
  const subscribe = ( listener ) => {
    listeners.push(listener);
    return ()=>{
      listeners = listeners.filter(l => l !== listener)
    }
  }

  return {
    getState,
    dispatch,
    subscribe
  }
}

Почему он не показывает, что вызов записиstore中изdispatch, это всеReact-Reduxсерединаconnectа такжеProviderкредит, если вы не используете их, вышеapp.jsКод должен быть следующим:

class Counter extends Component{

  componentWillMount(){
      // 订阅状态变化
    store.subscribe((state)=>this.setState(state))
  }

  render() {
    return (
      <div>
        <span>{value}</span>
        // 点击后dispatch事件类型
        <button onClick={()=>store.dispatch(increaseAction.increase())}>Increase</button>
      </div>
    )
  }
}

5.reducer()После выполнения функции, как изменитьstateиз?

см. вопрос 4createStoreКод можно упростить следующим образом:

function createStore = ( reducer ) => {

  let currentState; // 内部的状态

  const getState = () => currentState;  // 获取store中的state
  
  // 更新state
  const dispatch = ( action ) => {
    currentState = reducer(state, action); 
  }
  
  return {
    getState,
    dispatch,
  }
}

Вышеуказанные две проблемы были решены и объяснили поток данных в правой половине вышеуказанного рисунка.view——(action)——dispatch——(action)——reducer, два цикла данных объединяются вместе, чтобы сформировать круг, который завершает великую гармонию жизни. Как показано ниже:

Несколько редукторов

Прочитав приведенный выше анализ, давайте расширим, на картинке выше есть только одинreducer, в обычном приложении много представлений и, естественно, много соответствующихreducer, то интерфейсactionкак это соответствуетreducerА как насчет связанного?

Если вышеуказанный проект добавляетloginReducer.jsфайл, код такой:

loginReducer.js

// 提供一个初始的状态
initState={
 login: false
}

// 通过判断Action的类型,返回新的数据改变后的state对象,即使没有任何状态的改变,也要返回一个对象
export default function login(state = initState, action) {
  const login = state.login
  switch (action.type) {
    case INCREMENT:
      return { login: !login }
    default:
      return state
  }
}

этоreducerПросто выполните операцию, получитеINCREMENTПри этом типе операции состояние входа меняется один раз на обратное. Если я нажму кнопку еще раз, изменится ли статус входа в систему, когда число счетчиков увеличится? ответМогу! Так почему?

МогуПредпосылка: вы используете следующий код:

const rootReducer = combineReducers({
    counter: counter,
    login:login
});

store=createStore(rootReducer);

combineReducersОбъединитьreducer, так называемое слияние заключается в том, чтобы поставитьreducerФункциональные объекты объединены в единыйreducerФункция, она пройдет все подreducerчленов и интегрировать результаты в единое дерево состояний, поэтому существует только одинreducer, повторюсь, только один в концеreducerфункция!combineReducersГрубый код выглядит следующим образом:

export default function combineReducers(reducers) {

    var reducerKeys = Object.keys(reducers)
    var finalReducers = {}

    //提取reducers中value值为function的部分
    for (var i = 0; i < reducerKeys.length; i++) {
        var key = reducerKeys[i]
        if (typeof reducers[key] === 'function') {
            finalReducers[key] = reducers[key]
        }
    }
    var finalReducerKeys = Object.keys(finalReducers)

    return function combination(state = {}, action={}) {

        var hasChanged = false
        var nextState = {}
        /**
         * 遍历访问finalReducers
         */
        for (var i = 0; i < finalReducerKeys.length; i++) {
            var key = finalReducerKeys[i]
            var reducer = finalReducers[key]
            /**
             *将state按照reducer的名字分离
             * 每个key都对应着state
             */
            var previousStateForKey = state[key];
            var nextStateForKey = reducer(previousStateForKey, action)
  
            nextState[key] = nextStateForKey
            hasChanged = hasChanged || nextStateForKey !== previousStateForKey
        }
        return hasChanged ? nextState : state
    }
}

Из приведенного выше кода видно, что когдаdispatchОдинaction,всеreducerФункция будет выполнена один раз, поaction.typeизменить соответствующиеstate, чтобы все подписки соответствовалиstateизViewизменится. Итак, ответ на поставленный выше вопрос:Могу. Наконец, поставьте еще одну картинку, то есть несколькоreducerа такжеactionДиаграмма направления потока данных времени.

Как видно из рисунка,store,state,reducer,actionНа самом деле в итоге он один, мы просто делим его на несколько по логике кода, с четкими слоями, которые легко разрабатывать и читать.

Суммировать

Резюме предложения,ViewОтвечает за пользовательский интерфейс,reduxБудуViewсерединаstateи операции сосредоточены вstoreуправления, а затем черезpropsбудет измененstateсодержимое переданоViewИ интерфейс меняется. Пользовательский интерфейс,Viewпройти черезdispatchвыполнить соответствующие операции, а затемActionTypeа такжеDataсдаватьreducerфункция, согласноActionTypeа такжеDataИсправлятьstate.

Спасибо

наконец

Если вам это нравится, пожалуйста, хотите и следуйте.

Добро пожаловать в мойGitHubДомашняя страница, если хотитеfollowЯ.