Said front
In order to learn redux
, to achieve a just store
, createStore
, reducer
and some other basic functions
Now forget everything
First create a new project with the create-react-app, modify the public/index.html
structure of the page under
<body>
<div id='title'></div> <div id='content'></div> </body>
Empty src
folder, create a new index.js
, add code that represents the state we want to apply:
const appState = {
title: {
text: 'Redux',
color: 'red', }, content: { text: '学习redux', color: 'blue' } }
Add the rendering function, will render the above status data to the page:
function renderApp (appState) {
renderTitle(appState.title)
renderContent(appState.content)
}
function renderTitle (title) { const titleDOM = document.getElementById('title') titleDOM.innerHTML = title.text titleDOM.style.color = title.color } function renderContent (content) { const contentDOM = document.getElementById('content') contentDOM.innerHTML = content.text contentDOM.style.color = content.color }
Simple rendering is complete, but there will be a serious problem, rendering the data using a shared state appState
, anyone can modify , if we do operate other functions before rendering it unable to Chile Big East will appState
do what things, is why to avoid global variables
Between the different components when we need to share data, it is a contradiction:
❗❗ data shared data may be arbitrarily modified within the assembly between the components
If we learn about React team approach, the operation becomes complicated
Can be shared between components, but can not directly modify the data changes, you must perform some of the functions defined in I
Define a dispatch
function that is responsible for data modification
function dispatch (action) {
switch (action.type) { case 'UPDATE_TITLE_TEXT': appState.title.text = action.text break case 'UPDATE_TITLE_COLOR': appState.title.color = action.color break default: break } }
We operate on the data must pass through dispatch
function that takes one argument action
, which is a normal object, which contains a type
field to the life you want to do, dispatch
within switch
recognizes this field, identify successful will appState
be modified
The above dispatch
it can identify only two operations, one is UPDATE_TITLE_TEXT
that it will use action
the text
fields to update appState.title.text
; one is UPDATE_TITLE_COLOR
, it will use action
the color
fields to update appState.title.color
. action
Which in addition to type
field is required, other fields are customizable.
If you want to modify appState.title.text
, you must calldispatch
dispatch({ type: 'UPDATE_TITLE_TEXT', text: 'React.js' }) // 修改标题文本 dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色
So do not worry about the other functions will modify appState, at least directly modify
original:
Now all the data you want to modify must dispatch
:
Pulled outstore
Now, with appState
and dispatch
, we can put them together in one place, named called store
, and then build a createStore()
function, used to produce this state
and dispatch
collections
function createStore (state, stateChanger) {
const getState = () => state const dispatch = (action) => stateChanger(state, action) return { getState, dispatch } }
createStore
Takes two parameters, a state is represented state
, the other is stateChanger
, it is used to describe the state of the application based on action
what happens, equivalentdispatch
createStore
Returns an object that contains two methods getState
for acquiring state
the data, dispatch
modify the data, and as before
Now my code can be optimized to:
et appState = {
title: {
text: 'React.js',
color: 'red', }, content: { text: 'React.js 内容', color: 'blue' } } function stateChanger (state, action) { switch (action.type) { case 'UPDATE_TITLE_TEXT': state.title.text = action.text break case 'UPDATE_TITLE_COLOR': state.title.color = action.color break default: break } } const store = createStore(appState, stateChanger) renderApp(store.getState()) // 首次渲染页面 store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: 'React.js' }) // 修改标题文本 store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色 renderApp(store.getState()) // 把新的数据渲染到页面上
Then we have a difficult problem, how to monitor data changes, the above code, if we do not call renderApp
, the content of that page is not going to change, if to dispatch
add renderApp
, that we want universal createStore
die, would like to use a species common way monitor data, need to use the observer pattern:
function createStore (state, stateChanger) {
const listeners = [] const subscribe = (listener) => listeners.push(listener) const getState = () => state const dispatch = (action) => { stateChanger(state, action) listeners.forEach((listener) => listener()) } return { getState, dispatch, subscribe } }
在方法中定义了一个数组,还有一个subscribe
方法,可以通过这个方法传入一个监听函数,并push
到数组中,修改了dispatch
方法,当它被调用的时候,会遍历数组中的函数,一个个的调用,这就意味着我们可以通过subscribe
传入数据变化的监听函数,每次dispatch
的时候,监听函数都会被调用
const store = createStore(appState, stateChanger)
store.subscribe(() => renderApp(store.getState()))
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: 'UPDATE_TITLE_TEXT', text: 'React.js' }) // 修改标题文本 store.dispatch({ type: 'UPDATE_TITLE_COLOR', color: 'blue' }) // 修改标题颜色 // ...后面不管如何 store.dispatch,都不需要重新调用 renderApp
只需要subscribe
一次,后面不管怎么dispatch
,renderApp
都会被重新调用,重新渲染页面,而且观察者模式下同一块数据也可以渲染其他页面。
阶段总结
现在有了通用的createStore
,可以产生一种新定义的数据类型store
,通过getState
获取状态,dispatch
修改状态,subscribe
监听数据……