日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React个人入门总结《五》

發布時間:2025/3/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React个人入门总结《五》 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡介

這一次總結的是 React-redux 的實現,可以參考一下 大佬的文章 。

首先要知道 redux 的基本使用:

  • 創建一個 Store 。

    <!-- store --> function createStore (reducer) {let state = nullconst listeners = []const subscribe = (listener) => listeners.push(listener)const getState = () => stateconst dispatch = (action) => {state = reducer(state, action)listeners.forEach((listener) => listener())}dispatch({}) // 初始化 statereturn { getState, dispatch, subscribe } }<!-- reducer --> const themeReducer = (state = {}, action) => {switch (action.type) {case 'CHANGE_COLOR':return { ...state, themeColor: action.themeColor }default:return state} }<!-- 創建 store --> const store = createStore(themeReducer) 復制代碼

    Store 是保存數據的地方,整個應用只有一個,調用 CreateStore 函數并且傳入一個 Reducer 來創建一個 Store,并且會返回新的 Store 對象。

  • 獲取當前的 State。

    <!-- 調用 store.getState 獲取當前的狀態 --> const state = store.getState() 復制代碼

    State 是 Store 里面包含的數據對象,可以通過 Store.getState() 獲取

  • 通過 Dispatch 發送 Action 改變 State。

    <!-- 調用 dispatch 發送 action --> store.dispatch({type: 'CHANGE_COLOR',themeColor: 'blue' }) 復制代碼

    Action 就是 View 發出的通知,表示 View 要變化,其中 Type 是必須的,其余可以 自定義 。

    如果要寫多個 Action 覺得麻煩,可以使用 Action Creator 函數來生產 Action 。

    function updateThemeColor (action) {type: action.type,themeColor: action.themeColor }store.dispatch( updateThemeColor({ type: 'CHANGE_COLOR', themeColor: 'blue' }) ) 復制代碼
  • Reducer 是 Store 收到 Action 之后用來計算 State 并且返回新的 State,也就是說必須要有 Return 。

    <!-- reducer --><!-- 初始 state 是必須的,redux 規定不能為 undefined 和 null --> const themeReducer = (state = {}, action) => {switch (action.type) {case 'CHANGE_COLOR':return { ...state, themeColor: action.themeColor }default:return state} } 復制代碼

    Reducer 可以根據不同的 Type 來進行不同的邏輯處理,并且每次都會返回新的 state 來覆蓋原來的 state 。

    Reducer 是一個純函數,同樣的輸入就會得到同樣的輸出。

    Reducer 必須要返回一個新的狀態,而不是改變原有的狀態,請參考下面寫法:

    // State 是一個對象 function reducer(state, action) {return Object.assign({}, state, { thingToChange });// 或者return { ...state, ...newState }; }// State 是一個數組 function reducer(state, action) {return [...state, newItem]; } 復制代碼
  • 調用 subscribe 傳入一個函數,狀態改變時會調用此函數。

    store.subscribe(()=> {ReactDOM.render() }) 復制代碼

    Store.subscribe 方法設置監聽函數,一旦 State 發生變化,就自動執行這個函數。

    一般傳入 render 和 this.setState() 來監聽頁面重新渲染。

    調用此方法會返回一個函數,調用函數之后可以解除監聽。


  • React-redux

    首先之前向組件傳遞參數時,第一次使用的是 狀態提升,即通過父級傳入一個函數然后拿到組件里面的東西,再傳入另一個組件里面。

    當嵌套的太多層時,使用 狀態提升 會非常麻煩,然后第二次就開始使用了 Context ,由于 Context 能隨意被改變,這時我們可以把 ContextStore 結合使用,這樣就不能隨意的改變 Context ,并且狀態還能共享。

    import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; // 引入組件 import { Header } from './component/Header'; import { Content } from './component/Content'; import * as serviceWorker from './serviceWorker'; <!-- store --> function createStore(reducer) {let state = null;const listeners = [];const subscribe = (listener) => listeners.push(listener);const getState = () => state;const dispatch = (action) => {state = reducer(state, action);listeners.forEach((listener) => listener());}dispatch({});return { getState, dispatch, subscribe }; } <!-- reducer --> const themeReducer = (state, action) => {if (!state) return {themeColor: 'red'}switch (action.type) {case 'CHANGE_COLOR':return { ...state, themeColor: action.themeColor }default:return state} } <!-- 創建 store --> const store = createStore(themeReducer);class Index extends Component {<!-- 設置子組件的 contextType -->static childContextTypes = {store: PropTypes.object}<!-- 設置 context -->getChildContext() {return { store }}render() {return (<div className="index"><Header /><Content /></div>)} }ReactDOM.render(<Index />, document.getElementById('root')); 復制代碼

    創建 store 然后把它放到 context 里面,這樣所有子組件都可以拿到了。

    <!-- Header --> import React, { Component } from 'react'; import PropTypes from 'prop-types';class Header extends Component {static contextTypes = {store: PropTypes.object }constructor(props) {super(props);this.state = {themeColor: ''}}componentWillMount() {let { store } = this.context;this._updateThemeColor();store.subscribe(() => this._updateThemeColor())}_updateThemeColor() {let state = this.context.store.getState();this.setState({themeColor: state.themeColor})}render() {return (<div className="header"><h1 style={{color: this.state.themeColor}}>is header</h1></div>)} } export { Header };<!-- Content--> import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { ThemeSwitch } from './ThemeSwitch';class Content extends Component {static contextTypes = {store: PropTypes.object}componentWillMount() {let { store } = this.context;this._updateThemeColor();store.subscribe(() => this._updateThemeColor())}_updateThemeColor() {let state = this.context.store.getState();this.setState({themeColor: state.themeColor})}render() {return (<div className="header"><h2 style={{ color: this.state.themeColor }}>is Content</h2><ThemeSwitch /></div>)} } export { Content };<!-- ThemeSwitch --> import React, { Component } from 'react'; import PropTypes from 'prop-types';class ThemeSwitch extends Component {static contextTypes = {store: PropTypes.object}componentWillMount() {let { store } = this.context;this._updateThemeColor();store.subscribe(() => this._updateThemeColor())}_updateThemeColor() {let state = this.context.store.getState();this.setState({themeColor: state.themeColor})}render() {return (<div className="header"><button style={{ color: this.state.themeColor }}>red</button><button style={{ color: this.state.themeColor }}>blue</button></div>)} }export { ThemeSwitch }; 復制代碼

    上面三個子組件使用 store.getState() 獲取到 reducer 設置的默認狀態,這樣的話就可以實現共享狀態了。

    接下來我們實現點擊按鈕改變顏色:

    <!-- ThemeSwitch --> updateThemeColor(color) {let { store } = this.context;store.dispatch({type: 'CHANGE_COLOR',themeColor: color}) }render() {return (<div className="header"><button style={{ color: this.state.themeColor }} onClick={this.updateThemeColor.bind(this, 'red')}>red</button><button style={{ color: this.state.themeColor }} onClick={this.updateThemeColor.bind(this, 'blue')}>blue</button></div>) } 復制代碼

    調用 dispatch 然后傳入 action ,然后會調用 reducer 函數,然后根據傳入的 action.type 改變狀態,之后再返回一個新的狀態。

    返回新狀態時要想監聽頁面的更新,可以在 subscribe 傳入要監聽的函數,這樣就可以在調用 dispatch 同時會調用你傳入的函數,然后再一次調用 this.setState 觸發頁面重新渲染。

    _updateThemeColor() {<!-- 重新獲取一次狀態 -->let state = this.context.store.getState();<!-- 重新設置,并且觸發重新渲染 -->this.setState({themeColor: state.themeColor})}componentWillMount() {let { store } = this.context;<!-- 首次渲染 -->this._updateThemeColor();store.subscribe(() => this._updateThemeColor())} 復制代碼

    connect

    上面的組件有著重復的邏輯,首先取出 storestate 然后設置成自己的狀態,還有一個就是對 context 依賴過強,這時我們可以利用 高階組件 來和 context 打交道,這時就不用每個組件都獲取一遍 store 了。

    import React, { Component } from 'react'; import PropTypes from 'prop-types'; <!-- 接受一個組件 --> const connect = (WrappedComponent) => {class Connect extends Component {static contextTypes = {store: PropTypes.object}render() {const { store } = this.context;return <WrappedComponent />}}return Connect; } export { connect }; 復制代碼

    connect 是用于從 UI 組件生成 容器組件 ,也就是說我們傳入的組件只是負責呈現和展示,而 容器組件 負責業務邏輯和帶有內部狀態,connect 負責的是將兩者合并起來,生成并返回新的組件。

    由于每個傳進去的組件需要的 store 里面的數據都不一樣,所以我們還要傳入一個函數來告訴 高階組件 正確獲取數據。

    • mapStateToProps
    const mapStateToProps = (state) {return {themeColor: state.themeColor} } 復制代碼

    mapStateToProps 是一個獲取 store 保存的狀態,然后將這個狀態轉化為 UI組件 的數據的函數,它必須要返回一個對象,而這個對象用來進行狀態轉化的。

    import React, { Component } from 'react'; import PropTypes from 'prop-types';const connect = (mapStateToProps) => (WrappedComponent) => {class Connect extends Component {static contextTypes = {store: PropTypes.object}render () {const { store } = this.context;<!-- 從store獲取state并且轉化之后全部傳入 props -->let stateProps = mapStateToProps(store.getState());return <WrappedComponent {...stateProps} />}}return Connect; }export { connect }; 復制代碼

    上面最關鍵的一步就是調用 mapStateToProps 時,從 store 獲取到 state 之后然后傳入到 mapStateToProps 函數中,然后這函數會返回一個轉化后的 state ,然后把這些轉化的狀態全部傳入 props 里面。

    可以看出 connectDumb組件(純組件)context 連起來了,下面只需要調用 connect 然后傳入一個 mapStateToPropsUI組件 就可以使用了。

    <!-- Header --> import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from './React-redux';class Header extends Component {static propTypes = {themeColor: PropTypes.string}render() {return (<div className="header"><h1 style={{color: this.props.themeColor}}>is header</h1></div>)} } const mapStateToProps = (state) => {return {themeColor: state.themeColor} }Header = connect(mapStateToProps)(Header) export { Header };<!-- Content --> import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from './React-redux'; import { ThemeSwitch } from './ThemeSwitch';class Content extends Component {static propTypes = {themeColor: PropTypes.string}render() {return (<div className="header"><h2 style={{ color: this.props.themeColor }}>is Content</h2><ThemeSwitch /></div>)} }const mapStateToProps = (state) => {return {themeColor: state.themeColor} }Content = connect(mapStateToProps)(Content) export { Content }; 復制代碼

    由于 mapStateToProps 返回的對象經過 connect 傳入組件的 props 中,我們直接可以用 this.props 直接獲取到。

    接著把 connect 的代碼復制到一個叫 React-redux 的文件,然后可以刪掉之前那些引入 store 的代碼了。

    現在點擊按鈕只有按鈕會變顏色,接下來我們修改一下 connect

    import React, { Component } from 'react'; import PropTypes from 'prop-types';const connect = (mapStateToProps) => (WrappedComponent) => {class Connect extends Component {static contextTypes = {store: PropTypes.object}constructor (props) {super(props);this.state = { allProps: {}}}componentWillMount () {const { store } = this.context;this._updateProps();store.subscribe(() => this._updateProps())}_updateProps () {const { store } = this.context<!-- 現在 mapStateToProps 可以接受兩個參數 -->let stateProps = mapStateToProps(store.getState(), this.props)<!-- 整合普通的 props 和從 state 生成的 props -->this.setState({allProps: {...stateProps,...this.props}})}render () {return <WrappedComponent { ...this.state.allProps } />}}return Connect; } export { connect }; 復制代碼

    每次點擊按鈕調用 dispatch 都會把心的 state 設置到自己的 state 之后,然后返回給組件,這樣組件之前的 props 也會保留,同時 mapStateToProps 可以接受第二個參數,這個參數為當前 UI組件props 。

    <!-- 第一個為 store 獲取到的 state , 第二個為當前 ui 組件的 props (不是最新的) --> const mapStateToProps = (state, props) => {console.log(state, props)return {themeColor: state.themeColor} } 復制代碼

    使用 props 作為參數后,如果容器組件的參數發生變化,也會引發 UI組件 重新渲染,connect 方法可以省略 mapStateToProps 參數,這樣 store 的更新不會引起組件的更新。

    • mapDispatchToProps
    const mapDispatchToProps = (dispatch, props) => {return {updateThemeColor: () => {dispatch({type: 'CHANGE_COLOR',payload: ''})}} } 復制代碼

    mapDispatchToPropsconnect 的第二個參數,用來建立 UI組件 的參數到 store.dispatch 方法的映射,它作為函數時可以接受兩個參數,一個是 dispatch ,一個則是 UI組件props

    mapDispatchToProps 可以定義 action 然后傳給 store

    import React, { Component } from 'react'; import PropTypes from 'prop-types';const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {class Connect extends Component {static contextTypes = {store: PropTypes.object}constructor (props) {super(props);this.state = { allProps: {}}}componentWillMount () {const { store } = this.context;this._updateProps();store.subscribe(() => this._updateProps())}_updateProps () {const { store } = this.contextlet stateProps = mapStateToProps? mapStateToProps(store.getState(), this.props): {}let dispatchProps = mapDispatchToProps? mapDispatchToProps(store.dispatch, this.props): {}this.setState({allProps: {...stateProps,...dispatchProps,...this.props}})}render () {return <WrappedComponent { ...this.state.allProps } />}}return Connect; } export { connect }; 復制代碼

    接受 mapDispatchToProps 作第二個參數,調用時把 dispatchprops 傳進去,返回 onClickUpdate 然后直接傳入 props 中返回給 UI組件 ,接著我們可以直接調用 this.props.onClickUpdate 然后調用 dispatch 來更新狀態。

    import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from './React-redux';class ThemeSwitch extends Component {static contextTypes = {onClickUpdate: PropTypes.func}<!-- 點擊調用 onClickUpdate -->updateThemeColor(color) {if(this.props.onClickUpdate) {this.props.onClickUpdate(color)}}render() {return (<div className="header"> <button style={{ color: this.props.themeColor }} onClick={this.updateThemeColor.bind(this, 'red')}>red</button><button style={{ color: this.props.themeColor }} onClick={this.updateThemeColor.bind(this, 'blue')}>blue</button></div>)} } <!-- 在真正的 react-redux 不一定是函數 --> const mapStateToProps = (state, props) => {return {themeColor: state.themeColor} } <!-- 在真正的 react-redux 可以是一個對象 --> const mapDispatchToProps = (dispatch, props) => {return {onClickUpdate: (color) => {dispatch({type: 'CHANGE_COLOR',themeColor: color})}} }ThemeSwitch = connect(mapStateToProps, mapDispatchToProps)(ThemeSwitch); export { ThemeSwitch }; 復制代碼

    這樣點擊按鈕之后又可以改變顏色了。

    Provider

    connect 方法生成容器后需要拿到 state 對象,目前咱們能拿到 store 是因為在 index.js 中設置了 context ,這樣會直接污染 index.js , React-redux 提供了 Provider 來充當最外層容器,這樣就不需要在 index 設置 context 了。

    class Provider extends Component {static propTypes = {store: PropTypes.object,children: PropTypes.any}static childContextTypes = {store: PropTypes.object}getChildContext () {return {store: this.props.store}}render () {return (<div>{this.props.children}</div>)} }export { Provider }; 復制代碼

    React-redux 的文件增加上面的代碼,其實也就是另外設置一個容器來替代之前 index.js 干的活,這里返回了 this.props.children ,也說明要用這個組件把其他的組件包起來。

    import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import { Provider } from './component/React-redux'; // 引入組件 import { Header } from './component/Header'; import { Content } from './component/Content'; import * as serviceWorker from './serviceWorker';function createStore(reducer) {let state = null;const listeners = [];const subscribe = (listener) => listeners.push(listener);const getState = () => state;const dispatch = (action) => {state = reducer(state, action);listeners.forEach((listener) => listener());}dispatch({});return { getState, dispatch, subscribe }; }const themeReducer = (state, action) => {if (!state) return {themeColor: 'red'}switch (action.type) {case 'CHANGE_COLOR':return { ...state, themeColor: action.themeColor }default:return state} }const store = createStore(themeReducer);class Index extends Component {render() {return (<div className="index"><Header /><Content /></div>)} }ReactDOM.render(<!-- 把 store 和 外層組件包起來 --><Provider store= { store }><Index /></Provider>, document.getElementById('root') ); 復制代碼

    Store 傳入給 Provider ,然后它把 store 設置成 context ,這樣其他子組件都能拿到 store ,并且把最外層容器包起來,然后使用 this.props.children 全部羅列出來。

    import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { connect } from './React-redux';class Header extends Component {<!-- 別忘了聲明這玩意,不然拿不到 -->static contextTypes = {store: PropTypes.object}static propTypes = {themeColor: PropTypes.string}componentWillMount() {console.log(this.context)}render() {return (<div className="header"><h1 style={{color: this.props.themeColor}}>is header</h1></div>)} } const mapStateToProps = (state, props) => {return {themeColor: state.themeColor} }Header = connect(mapStateToProps)(Header) export { Header }; 復制代碼

    拿到之后接下來就可以浪了,可以在當前組件調用里面的方法,非常靈活。

    總結

  • 首先在 index.js 引入創建好的 store ,然后引入 Provider 把 index 包起來,并且給它傳遞 store 。
  • 如果頁面需要拿到狀態直接調用 store.getState ,如果想監聽函數調用 store.subscribe 傳入函數。
  • 如果想訂閱 store 或者修改 state ,在當前組件引入 connect 接著傳入 mapStateToProps 和 mapDispatchToProps 來呈現新的 UI組件 。
  • dispatch 還可以拓展,真正的 react-redux 還可以使用中間件實現異步 action ,如需要從后臺返回的狀態來改變當前的 state 類似這種操作。
  • 可以使用 combineReducers 管理多個 reducer,一個 store 管理N種狀態。

  • 上一篇 --- React個人入門總結《四》

    下一篇 --- React個人入門總結《六》

    總結

    以上是生活随笔為你收集整理的React个人入门总结《五》的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。