19年的第一篇文章,雖然18年也沒有分享多少,可是19年開始,我以爲要好好學習,好好努力。固然新的一年伊始,祝你們在19年平安、幸福,還有發發發。css
redux解決的核心問題是父子兄弟等組件件傳值很麻煩的問題,因而有了一個"通信班"--redux,這個通信班能夠幫咱們把組件之間的狀態整合到一塊兒,而後修改也統一修改。咱們以爲很nice。上一篇文章我簡單的跟你們解讀了redux的工做原理。可是,修改完成之後,把修改的東西再通知下去咱們又會以爲是一個麻煩,咱們也但願能有這樣一個通信班來幫咱們把命令傳達下去。爲了解決這個問題,react-redux義無反顧的出現了。這樣相對來講就比較完美了。那今天咱們就會想把整個工做流都本身來簡單實現了,也便有了接下來的故事。redux、react-redux兄弟同心,齊力傳值。vue
redux三板斧,store、action,reducer。 以前簡單了作了一個redux。今天,把上次的代碼優化下,作個精緻的redux,可是其實裏面的東西都是差很少的。在這一部分的分享我也不會作太詳細的講解,若是過程當中有疑問能夠看下上篇文章,或者看完後不懂你們能夠留言互相交流。 createStore建立的對象擁有4個API,他們分管不一樣的職能。
react
export const createStore = (state,storeChange) => {
const listeners = [];
let store = state || {};
const subscribe = (listener) => {
listeners.push(listener)
}
const dispatch = (action) => {
const newStore = storeChange(store,action);
store = newStore;
listeners.forEach((item) => item())
}
const getStore = () => {
return store;
}
return {store,dispatch,subscribe,getStore}
}
複製代碼
subcribe使用訂閱發佈者模式。組件訂閱了,中央有改變的時候就會發布消息給他。訂閱的方式,經過一個監聽數組,把每一個組件的render函數都放到有個數組裏面,當數據改變後,咱們把全部訂閱了的組件的監聽函數從新執行一遍。這樣視圖層就獲得了改變。所以在dispatch的設計思想就是,先把reducer後的值拿過來,把它賦值給中央,再把組件的值更新下。 storeChange.js的代碼,使用es6解構語法以下:git
export const storeChange = (store,action) => {
switch (action.type) {
case "HEAD":
return {
...store,
head: action.head
}
case "BODY":
return {
...store,
body:action.body
}
default:
return { ...store}
}
}
複製代碼
reudx在大型項目中每每會有不少的輸出,所以咱們在此也用了一個設計模式,把輸出統一,這樣便於後期的維護和修改。index.js代碼以下:es6
export * from './createStore';
export * from './storeChange';
複製代碼
好了。來到今天的重磅嘉賓了。你以爲是react-redux。固然不是。而是react-redux的中流砥柱,context。github
Context是React的高級API ,使用context能夠實現跨組件傳值。在react-redux的中就是經過context提供一個全局的store ,拖拽組件的react-dnd,經過Context在組件中分發DOM的Drg和Drop事件。不只如此,路由組件react-router還能夠經過Context管理路由狀態等等,能夠說至關重量級的嘉賓了。 這是官方的一個描述: 面試
Context的使用基於生產者消費者模式。
父節點做爲Context的生產者,而消費者則是父節點下的全部的節點。父節點經過一個靜態屬性childContextTypes提供給子組件的Context對象屬性,並實現一個實例getChildCotext方法,返回一個Context純對象。而子組件經過一個靜態屬性contextTypes聲明後,才能訪問父組件的context對象屬性,不然即便屬性名沒有寫錯,拿到的對象也是undefined。 App.js咱們代碼設計以下:redux
import React, { Component } from "react";
import PropTypes from "prop-types"
import Body from "./component/body/Body"
import Head from "./component/head/Head"
import { createStore, storeChange} from './redux';
// import './App.css';
class App extends Component {
static childContextTypes = {
store: PropTypes.object,
dispatch: PropTypes.func,
subscribe: PropTypes.func,
getStore: PropTypes.func
}
getChildContext() {
const state = {
head: "我是全局head",
body: "我是全局body",
headBtn: "修改head",
bodyBtn: "修改body"
}
const { store,dispatch, subscribe,getStore } = createStore(state,storeChange)
return { store,dispatch,subscribe,getStore}
}
render() {
return (
<div className="App">
<Head />
<Body />
</div>
);
}
}
export default App;
複製代碼
static聲明一個ChildContextTypes,頂層組件規定要傳給子組件Context對象的屬性類型,一個getChildContext函數,返回給子組件一個純對象 ,子組件中接收,子組件目錄結構以下: 設計模式
import React, {Component} from 'react';
import Button from '../Button/Button';
import PropTypes from "prop-types";
export default class Body extends Component {
static contextTypes = {
store: PropTypes.object,
subscribe: PropTypes.func,
getStore: PropTypes.func
}
constructor(props) {
super(props);
this.state = {};
}
componentWillMount () {
const { subscribe } = this.context;
this._upState();
subscribe(()=> this._upState())
}
_upState() {
const { getStore } = this.context;
this.setState({
...getStore()
})
}
render () {
return (
<div>
<div className="body">{this.state.body}</div>
<Button/>
</div>
)
}
}
複製代碼
子組件經過一個contextTypes,用來接收父組件傳過來的屬性。組件中使用了狀態就表明他須要訂閱,所以咱們加載組件的時候就就組件的setState方法push到監聽函數裏面,這樣就能讓數據改變後頁面可以獲得從新渲染。關於setState這篇文章--setState這個API到底怎麼樣講解的挺詳細的,不是很明白setState背後的原理的骨子能夠看看。 同理貼上Head.js:數組
import React, {Component} from 'react';
import PropTypes from "prop-types"
export default class Head extends Component{
static contextTypes = {
store: PropTypes.object,
subscribe: PropTypes.func,
getStore: PropTypes.func
}
constructor(props) {
super(props);
this.state = { };
}
componentWillMount () {
const { subscribe } = this.context;
this._upState();
subscribe(()=> this._upState())
}
_upState() {
const { getStore } = this.context;
this.setState({
...getStore()
})
}
render() {
return (
<div className="head">{this.state.head}</div>
)
}
}
複製代碼
Button.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class Button extends Component {
static contextTypes = {
store: PropTypes.object,
dispatch: PropTypes.func,
subscribe: PropTypes.func,
getStore: PropTypes.func
}
constructor(props) {
super(props);
this.state = {};
}
componentWillMount() {
this._upState();
}
_upState() {
const { store } = this.context;
this.setState({
...store
})
}
changeContext(type) {
const { dispatch } =this.context;
const key = type === "HEAD" ? "head":"body";
dispatch({
type: type,
[key]: `我是修改後的${key}`
})
}
render () {
return (
<div className="button">
<div className="btn" onClick={() => {
this.changeContext("HEAD")
}}>改變head</div>
<div className="btn" onClick={() => {
this.changeContext("BODY")
}}>改變body</div>
</div>
)
}
}
複製代碼
整個流程走完,context的API在react-redux的用法就是這樣的了 這是效果:
context總共分爲四步:
後期React對Context作了調整,可是更方便咱們使用,有須要的能夠看下個人github上demo.js,一清二楚。
其實一步步慢慢去了解,就能發現萬事萬物真的皆是一理,以前面對兩個主流框架,react和vue,你們都說vue更簡單,更容易上手,因而就先學了vue,剛學習的時候,感受,好像也不難,後面在公司實習的時候,一直用,感受用的挺順手的。就以爲若是要用起來也就那麼回事。再到離職後,發現都在用react,去學react,也是一樣的感受。學習多是一個坎,堅持下跨過去了就行了。一個大三老油條[hahah]如今也是邊準備春招的實習面試,邊學習,邊寫文章。分享不到位或是不正確的地方望你們指正。