React:一個專注於 UI 的 javascript 前端庫#
Redux#
redux 是一個狀態管理庫,用於對整個 App 組件的共享狀態和數據進行集中式管理
store#
import { createStore } from 'redux'
const init = {
value:'defaultValue'
}
const store = createStore((state=init,action) => {
const { type, data } = action
switch(type){
case 'add':
return {...state,num:data}
default:
return state
}
})
export default store
派發 action#
import store from './store'
const actionCreator = (data) => {
return {
type:'add',
data
}
}
btnClick = () => {
const action = actionCreator(233)
store.dispatch(action)
}
獲取 store 值#
import store from './store'
class Home extends React.component{
componentDidMount(() => {
this.unSubscribe = store.subscribe(() => {
//監聽store狀態變化更新視圖
this.setState({})
})
})
componentWillUnmount(() => {
//取消監聽
this.unSubscribe()
})
render(){
return (
<>
<h2> { store.getState().num }</h2>
</>
)
}
}
react-redux#
react-redux 能夠使得在組件中更方便的派發 action 和獲取 store 中的數據,並且數據更新自動重新渲染組件
- Provider 一個組件用於包裹住最外層根組件,使得其子組件能夠共享狀態
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
);
- 函數式組件中發送 action 和獲取 store 中的值
import React, { memo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
export default memo(function Text() {
const dispatch = useDispatch();
const num = useSelector(state => state.num); //獲取值
const btnClick = () => {
//發送action
dispatch({
type: 'add',
num: 10,
});
};
return (
<div>
<h2></h2>
<button onClick={e => btnClick()}>發送action</button>
</div>
);
});
-
類組件中獲取 store 和發生 action ==> connect
connect 可以將組件和 store 進行關聯使得數據共享
import React from 'react'
import { connect } from 'react-redux'
class Home extends React.component {
const btnClick = () => {
this.props.sendAction()
}
<>
<button onClick={this.btnClick}>分發</button>
</>
}
export connect(
//參數一:redux中的state;參數二:組件自己的props
//返回值:對象,將該返回值傳遞到組件中的props中去
(state,ownProps)=>{ //接受
},
//參數一:dispatch函數,用於分發action;參數二:自己的props
//返回值:對象,它會將返回的該對象傳遞到Home組件中的props中去
(dispatch,ownProps)=>{ //發送
return {
sendAction:() => {
//利用dispatch發送一個action
dispatch({
type:'add',
num:1
})
}
}
}
)(Home)
完善代碼#
- store
import { createStore } from 'redux';
const init = {
value: '默認值',
num: 0,
};
function reducer(state = init, action) {
const { type, data } = action;
switch (type) {
case 'add':
return { ...state, num: data };
case 'sub':
return { ...state, num: data };
default:
return state;
}
}
export default createStore(reducer);
- 根組件
import React, { PureComponent } from 'react';
import { Provider } from 'react-redux';
import About from './pages/About';
import Home from './pages/Home';
import store from './store';
export default class App extends PureComponent {
render() {
return (
<Provider store={store}>
<Home ownProps={'嘻嘻嘻'} />
<hr />
<About />
</Provider>
);
}
}
- 類組件
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
class Home extends PureComponent {
btnClick = () => {
this.props.addAction();
};
render() {
return (
<div>
<h2>Home:類組件</h2>
<button onClick={this.btnClick}>+</button>
<h2>當前計數:{this.props.num}</h2>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return state;
};
const mapDispatchToProps = (dispatch, ownProps) => {
let num = 0;
return {
addAction: () => {
dispatch({
type: 'add',
data: ++num,
});
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
- 函數式組件
import React, { memo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
export default memo(function About() {
const dispatch = useDispatch();
const num = useSelector(state => state.num);
const btnClick = () => {
let temNum = num;
dispatch({
type: 'sub',
data: --temNum,
});
};
return (
<div>
<h2>About:函數式組件</h2>
<button onClick={btnClick}>-</button>
<h2>當前計數{num}</h2>
</div>
);
});
combineReducers(reducers)#
- reducers/todos.js
export default function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([action.text]);
default:
return state;
}
}
- reducers/counter.js
export default function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
- reducers/index.js
import { combineReducers } from 'redux';
import todos from './todos';
import counter from './counter';
export default combineReducers({
todos,
counter,
});
- App.js
import { createStore } from 'redux';
import reducer from './reducers/index';
let store = createStore(reducer);
console.log(store.getState());
// {
// counter: 0,
// todos: []
// }
store.dispatch({
type: 'ADD_TODO',
text: 'Use Redux',
});
console.log(store.getState());
// {
// counter: 0,
// todos: [ 'Use Redux' ]
// }
Mobx#
store#
import { action, computed, runInAction, makeAutoObservable, flow } from 'mobx';
export class CounterStore {
// 定義數據
count = 0;
list = [1, 2, 3, 4, 5];
asyncData = 0;
flowData = 'default';
constructor() {
// 將數據變成響應式
makeAutoObservable(this, {
// 可以標記 | 也可以不標記
incrementCount: action,
decrementCount: action,
changeFilterList: action,
asyncAdd: action,
asyncFlow: action.bound,
filterList: computed,
});
}
// 定義 action 函數用於修改數據
incrementCount = () => {
this.count++;
};
decrementCount = () => {
this.count--;
};
changeFilterList = () => {
this.list.push(...[5, 4, 3, 2, 1]);
};
// 異步action(使用runInAction包裹)
asyncAdd = async () => {
await Promise.resolve();
runInAction(() => {
this.incrementCount();
this.asyncData++;
});
};
// 異步action(使用 flow )
asyncFlow = flow(function* () {
yield console.log(this); //需要綁定 this
const data = yield Promise.resolve('Flow');
this.flowData = data;
});
// 定義computed
get filterList() {
return this.list.map(item => item * 2);
}
}
根 Store#
import { CounterStore } from './counter';
class Store {
constructor() {
this.counter = new CounterStore();
}
}
const store = new Store();
export { store };
store 共享#
使用 context
import React, { createContext } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { store } from './store';
export const Context = createContext();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Context.Provider value={store}>
<App />
</Context.Provider>
);
在組件中使用#
import React, { memo, useContext } from 'react';
import { observer } from 'mobx-react-lite';
import { Context } from '../..';
const Counter = () => {
const {
counter: {
count,
changeFilterList,
asyncData,
flowData,
decrementCount,
filterList,
incrementCount,
asyncAdd,
asyncFlow,
},
} = useContext(Context);
return (
<div>
<button onClick={incrementCount}>+</button>
<span>{count}</span>
<button onClick={decrementCount}>-</button>
{filterList.map((i, n) => {
return <li key={n}>{i}</li>;
})}
<button onClick={changeFilterList}>添加數組</button>
<hr />
<span>{asyncData}</span>
<button onClick={asyncAdd}>異步runInAction</button>
<hr />
<span>{flowData}</span>
<button onClick={asyncFlow}>異步flow</button>
</div>
);
};
export default memo(observer(Counter));