美文网首页
React学习笔记4-深入Redux

React学习笔记4-深入Redux

作者: 波拉拉 | 来源:发表于2020-06-22 22:05 被阅读0次
    这篇六个点:1 Redux简介 2 中间件 3 异步流 4 Redux与路由 5 Redux与组件 6 应用实例。

    4.1 Redux简介

    Redux核心运行流畅
    4.1.1 Redux三大原则

    1 单一数据源
    在Redux思想里,一个应用只有唯一的数据源,好处是整个应用状态都保存在一个对象中,可以随时取出整个应用的状态进行持久化,这样的设计页尾服务端渲染提供了可能。
    2 状态是只读的
    在Redux中,并不会自己定义一个store,而是定义一个reducer,reducer根据当前触发的action对当前应用的状态进行更新
    3 状态修改均由纯函数完成
    在redux里,通过定义reducer来确定状态的修改,每一个reducer都是纯函数,接受一定的输入,必定得到一定的输出。

    4.1.2 Redux四个部分

    整体结构

    import { createStore} from 'redux';
    // reducer部分
    const defaultState={
        myValue:[],
        inputValue:"默认值"
    };
    function reducer(state=defaultState,action) {
        if (action.type==="add"){
            const newState=JSON.parse(JSON.stringify(state));
            newState.myValue.push(newState.inputValue);
            console.log(newState);
            return newState;
        }
        if (action.type==='change'){
            const newState=JSON.parse(JSON.stringify(state));
            newState.inputValue=action.value;
            console.log(newState);
            return newState;
    
        }
        return state;
    }
    // store 部分
    const store=createStore(
        reducer,
        window.__REDUX_DEVTOOLS_EXTENSION__&&window.__REDUX_DEVTOOLS_EXTENSION__()
    );
    
    class ReduxTest extends Component{
        constructor(props){
            super(props);
            this.state=store.getState();
            console.log(this.state);
            this.handleClick=this.handleClick.bind(this);
            this.handleChange=this.handleChange.bind(this);
            // 状态改变就执行
            store.subscribe(()=>{
                this.setState(store.getState());
            });
        }
        handleClick(){
            const action={
                type:'add'
            };
            store.dispatch(action);
        }
        handleChange(e){
            const action={
                type:'change',
                value:e.target.value
            };
            store.dispatch(action);
        }
        render(){
            return(
                <div>
                    <input
                        value={this.state.inputValue||"HAHA"}
                        onChange={this.handleChange}
                    />
                    <button onClick={this.handleClick}>改变</button>
                </div>
            )
        }
    }
    
    1. store
    import { createStore} from 'redux';
    const store=createStore(
        reducer,
        window.__REDUX_DEVTOOLS_EXTENSION__&&window.__REDUX_DEVTOOLS_EXTENSION__()
    );
    

    Redux最核心的API,可以创建一个store对象,store又包含4个方法。
    getState():获取store中当前的状态。
    dispatch(action):分发一个action并返回这个action,这是唯一能改变store中数据的方式。
    subscribe():注册一个监听者,当store发生变化时会被调用。

    1. action
      唯一可以改变状态就是触发action,它是一个普通对象,用于描述已经发生的事件。type是必须的,其他可以自定义。
    handleChange(e){
            const action={
                type:'change',
                value:e.target.value
            };
            store.dispatch(action);
        }
    //实际这么用
    function addTo(e){
        return{
            type:'change',
            value:e.target.value
        }
    }
    handleChange(e){
            store.dispatch(addTo(e));
        }
    
    1. reducer
      通过dispatch发起action之后,最终是通过reducer指定如何state,reducer是用来修改状态的,要注意的是不要在reducer中直接修改state,推荐创建一个新的移入,重新通过getState返回新的状态,最终通过subscribe重新渲染。
    2. connect

    4.2 中间件

    https://www.jianshu.com/p/ae7b5a2f78ae

    11.png
    这是redux的数据流流程,当增加middleware后,就可以在途中对action进行截获。
    。且由于业务场景的多样性,单纯的修改 dispatch 和 reduce 人显然不能满足大家的需要,因此对 redux middleware 的设计是可以自由组合,自由插拔的插件机制。也正是由于这个机制,我们在使用 middleware 时,我们可以通过串联不同的 middleware 来满足日常的开发,每一个 middleware 都可以处理一个相对独立的业务需求且相互串联:
    22.png
    如上图所示,派发给 redux Store 的 action 对象,会被 Store 上的多个中间件依次处理,如果把 action 和当前的 state 交给 reducer 处理的过程看做默认存在的中间件,那么其实所有的对 action 的处理都可以有中间件组成的。值得注意的是这些中间件会按照指定的顺序一次处理传入的 action,只有排在前面的中间件完成任务之后,后面的中间件才有机会继续处理 action,同样的,每个中间件都有自己的“熔断”处理,当它认为这个 action 不需要后面的中间件进行处理时,后面的中间件也就不能再对这个 action 进行处理了。

    而不同的中间件之所以可以组合使用,是因为 Redux 要求所有的中间件必须提供统一的接口,每个中间件的尉氏县逻辑虽然不一样,但只要遵循统一的接口就能和redux以及其他的中间件对话了。

    4.3 Redux异步流

    • 1 redux-thunk中间件
      redux-thunk是用于在redux中处理异步action的中间件,它 统一了异步和同步action的调用方式,使得异步过程放在action级别解决,避免异步操作对component的耦合。
      使用这个插件,可以让action创建函数先不返回一个action对象,而是返回一个函数,函数传递两个参数(dispatch,getState)
    import React, {Component} from 'react';
    import ReactDOM from 'react-dom';
    import { createStore,applyMiddleware} from 'redux';
    import thunk from 'redux-thunk';
    
    // reducer部分
    const defaultState={
        myValue:[],
        inputValue:"默认值",
        num:3
    };
    function reducer(state=defaultState,action) {
        if (action.type=='addValue'){
            const newState=JSON.parse(JSON.stringify(state));
            newState.num++;
            console.log(newState);
            return newState;
        }
        return state;
    }
    
    // store 部分
    const store=createStore(
        reducer,
        applyMiddleware(thunk)
    );
    class Thunk extends Component{
        constructor(props){
            super(props);
            this.state=store.getState();
            // console.log(this.state);
            this.handleClick=this.handleClick.bind(this);
            this.handleChange=this.handleChange.bind(this);
            // 状态改变就执行
            store.subscribe(()=>{
                this.setState(store.getState());
            });
        }
        addIfOdd(){
            return (dispatch,getState)=>{
                console.log('111');
                if (this.state.num%2===0){
                    return false
                }else {
                   setTimeout(()=>{
                       dispatch({type:'addValue'})
                   },2000)
                }
            }
        }
        handleClick(){
            store.dispatch(this.addIfOdd());
            console.log("222")
        }
        
        handleChange(){}
        
        render(){
            return(
                <div>
                    <input
                        value={this.state.num||"HAHA"}
                        onChange={this.handleChange}
                    />
                    <button onClick={this.handleClick}>改变</button>
                </div>
            )
        }
    }
    
    • Redux-saga 略

    4.4 Redux与路由

    http://www.ruanyifeng.com/blog/2016/05/react_router.html

    import {BrowserRouter,Route} from 'react-router-dom';
    //要渲染组件内的render
    render() {
            return (
                <div>
                    <input
                        value={this.state.num || "HAHA"}
                        onChange={this.handleChange}
                    />
                    <button onClick={this.handleClick}>改变</button>
                    <BrowserRouter>
                        <Route path='/' exact render={() => <div>首页</div>}/>
                        <Route path='/detail' exact render={() => <div>详情页</div>}/>
                    </BrowserRouter>
                </div>
            )
        }
    ReactDOM.render(
        <Thunk/>,
        document.getElementById('root'),
        function () {
            console.log("加载完毕");
        }
    );
    

    4.5 Redux与组件

    4.5.1 容器型组件
    4.5.2 展示型组件
    4.5.3 Redux中的组件

    4.6 应用实例

    mkdir my-blog
    cd my-blog
    G:\react\my-blog> npm install --save react react-dom redux react-router react-redux react-router-redux whatwg-fetch
    

    https://www.jianshu.com/p/6a45e2dfc9d9/

    文件结构
    app.js:整个应用的入口
    views文件夹:页面的入口文件,常在路由中引用
    components文件夹:下面对应页面的文件夹,里面一堆组件
    containers :配置文件
    layouts:公用的组件和样式。如菜单,header等
    redux:Redux store相关的配置
    routes:路由相关的配置

    -views/Home.js

    import React,{Component} from 'react';
    class Home extends Component {
        constructor(props){
            super(props);
        };
        render(){
            return(
                <h1>Home</h1>
            )
        }
    }
    export default Home;
    
    • views/Detail.js
    import React,{Component} from 'react';
    class Detail extends Component {
        constructor(props){
            super(props);
        };
        render(){
            return(
                <h1>Detail</h1>
            )
        }
    }
    export default Detail;
    
    • route/index.js
    import React from 'react';
    import {BrowserRouter,Route} from 'react-router-dom';
    import Home from '../views/Home';
    import Detail from '../views/Detail';
    const routes=(
        <BrowserRouter>
            <Route path='/' component={Home}/>
            <Route path='/detail' component={Detail}/>
        </BrowserRouter>
    );
    export default routes;
    
    • app.js
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    import {BrowserRouter,Route} from 'react-router-dom';
    import routes from './routes';
    function App() {
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              Edit <code>src/App.js</code> and save to reload.
            </p>
            <a className="App-link" href="https://reactjs.org"
              target="_blank" rel="noopener noreferrer"
            >
              Learn React
            </a>
          </header>
            {routes}
        </div>
      );
    }
    export default App;
    
    • index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import * as serviceWorker from './serviceWorker';
    
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
    serviceWorker.unregister();
    
    • index.html
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="theme-color" content="#000000" />
        <meta
          name="description"
          content="Web site created using create-react-app"
        />
        <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
        <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
        <title>React App</title>
      </head>
      <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root"></div>
      </body>
    </html>
    

    添加公用的组件
    lauouts/Nav.js

    import React,{Component} from 'react';
    import {BrowserRouter as Router, Link} from 'react-router-dom';
    class Nav extends Component {
        constructor(props){
            super(props);
        };
        render(){
            return(
                <nav>
                    <Link to='/'>首页</Link>
                </nav>
            )
        }
    }
    export default Nav;
    

    lauouts/Frame.js

    import React,{Component} from 'react';
    import {Link} from 'react-router-dom';
    import Nav from './Nav';
    class Frame extends Component {
        constructor(props){
            super(props);
        };
        render(){
            return(
               <div>
                   <Nav/>
               </div>
            )
        }
    }
    export default Frame;
    

    修改routes/index.js

    import React from 'react';
    import {BrowserRouter,Route} from 'react-router-dom';
    import Home from '../views/Home';
    import Detail from '../views/Detail';
    import Frame from '../layouts/Frame'
    const routes=(
        <BrowserRouter>
            <Frame/>
            <Route path='/' component={Home}/>
            <Route path='/detail' component={Detail}/>
        </BrowserRouter>
    );
    export default routes;
    

    继续修改App.js

    
    import React from 'react';
    import logo from './logo.svg';
    import './App.css';
    import {BrowserRouter,Route} from 'react-router-dom';
    import routes from './routes';
    function App() {
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              Edit <code>src/App.js</code> and save to reload.
            </p>
            <a className="App-link" href="https://reactjs.org"
              target="_blank" rel="noopener noreferrer"
            >
              Learn React
            </a>
          </header>
            {routes}
        </div>
      );
    }
    export default App;
    

    成功实现路由

    准备首页的数据
    P242 后面看不懂 略

    相关文章

      网友评论

          本文标题:React学习笔记4-深入Redux

          本文链接:https://www.haomeiwen.com/subject/suwffktx.html