предисловие
В настоящее время изучает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.
Спасибо
- Подробное объяснение метода подключения реакции-редукции
- редукционная китайская маркировка
- Использование React-Redux
наконец
Если вам это нравится, пожалуйста, хотите и следуйте.
Добро пожаловать в мойGitHubДомашняя страница, если хотитеfollowЯ.