【问题标题】:Add Redux in React project在 React 项目中添加 Redux
【发布时间】:2019-04-21 21:24:06
【问题描述】:

在 React 项目中添加 redux(用 Redux 重构一个简单的项目)

考虑一个简单的项目,一个使用两个按钮的计数器应用程序,一个用于增量,另一个用于减量计数器值。

在实际场景中,我们使用 state 来保存计数器值,如下所示:

App.js 中:

import React, {Component} from 'react';
import CounterApp from './CounterApp'

class App extends Component {
  render() {
    return (
      <CounterApp/>
    );
  }
}

export default App;

CounterApp.js 中:

import React, {Component} from 'react';

class CounterApp extends Component {
  state = {
    counter: 0
  };

  handleIncrement = () => {
    this.setState(prevState => ({
      counter: prevState.counter + 1
    }))
  };

  handleDecrement = () => {
    this.setState(prevState => ({
      counter: prevState.counter - 1
    }))
  };

  render() {
    return (
      <div>
        <button onClick={this.handleIncrement}>Increment</button>
        <p>{this.state.counter}</p>
        <button onClick={this.handleDecrement}>Decrement</button>
      </div>
    );
  }
}

export default CounterApp;

一个简单而基本的示例,使用 react 类组件实现并由两个函数处理程序(handleIncrementhandleDecrement)处理

还有一个state,其值为counter

我正在使用prevState,因为这是您在setState 中强制使用this.state. 时的最佳做法!

现在,用 Redux 实现什么?

【问题讨论】:

    标签: javascript reactjs react-native redux


    【解决方案1】:

    首先,您需要通过npmyarnreduxreact-redux 包安装到您的项目中。

    你可以用一行代码简单地安装它们:

    npm install redux react-redux --save
    

    或者用纱线:

    yarn add redux react-redux
    

    现在回到项目并使用这些名称创建 3 个文件:

    action.jsreducer.jsstore.js

    打开action.js 文件。我们应该为这个应用程序实现两个动作。一个是递增的,一个是递减的。

    action.js

    const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
    const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
    
    const increment = () => ({type: INCREMENT_COUNTER});
    const decrement = () => ({type: DECREMENT_COUNTER});
    
    export {
      INCREMENT_COUNTER,
      DECREMENT_COUNTER,
      increment,
      decrement
    }
    

    actions 是从组件分发到 redux 的简单函数 用于通过 reducers 更改 store(state)。

    所以我们应该改变 reducer.js

    import {INCREMENT_COUNTER, DECREMENT_COUNTER} from "./action";
    
    const initialState = {
      counter: 0
    };
    
    const reducer = (state = initialState, action) => {
      switch (action.type) {
        case(INCREMENT_COUNTER):
          return {
            ...state,
            counter: state.counter + 1
          };
        case (DECREMENT_COUNTER):
          return {
            ...state,
            counter: state.counter - 1
          };
        default:
          return state
      }
    };
    
    export default reducer
    

    使用redux有3个主要原则:

    1- 单一事实来源。您的整个应用程序的状态是 存储在单个存储中的对象树中。

    2- 状态是只读的。改变状态的唯一方法是发射 一个动作,一个描述发生了什么的对象。

    3- 使用纯函数进行更改。

    根据第二个原则,我们必须假设状态是不可变的,并且每个 case(in switch) 必须单独返回状态。 在返回的状态中使用 ...state 意味着如果 initialState 将来会发生变化,这些情况将正常工作(在本例中没有必要)。

    我们在行动中的功能是纯粹的(第三条原则)

    最后一个新文件store.js

    import {createStore} from "redux";
    import reducer from './reducer'
    
    const store = createStore(reducer);
    
    export default store;
    

    现在我们应该将此商店应用到我们的 App 组件。 所以打开 App.js 文件并进行以下更改:

    App.js 中:

    import React, {Component} from 'react';
    import CounterApp from './CounterApp'
    import {Provider} from 'react-redux'
    import store from './store'
    
    class App extends Component {
      render() {
        return (
          <Provider store={store}>
            <CounterApp/>
          </Provider>
        );
      }
    }
    
    export default App;
    

    Provider 包装了CounterApp 组件,并将store 传播到AppCounterApp 以及所有其他子组件。

    最后,更改 CounterApp.js

    import React, {Component} from 'react';
    import {connect} from "react-redux";
    import {increment, decrement} from "./action";
    
    class CounterApp extends Component {
    
      handleIncrement = () => this.props.dispatch(increment());
    
      handleDecrement = () => this.props.dispatch(decrement());
    
      render() {
        return (
          <div>
            <button onClick={this.handleIncrement}>Increment</button>
            <p>{this.props.counter}</p>
            <button onClick={this.handleDecrement}>Decrement</button>
          </div>
        );
      }
    }
    
    const mapStateToProps = state => {
      const counter = state.counter;
      return {counter}
    };
    
    export default connect(mapStateToProps)(CounterApp);
    

    我们正在使用 incrementdecrement 动作将动作分派给 redux。

    state 已被移除,我们创建了一个特殊函数 mapStateToProps' and useconnect` 来代替 state,将 state 连接到组件 props。

    大功告成!

    【讨论】:

    • redux 的实现有很多,但是对于它来说这是一个非常简单的过程。例如,使用 mapDispatchToProps 等等...
    【解决方案2】:

    如果你需要在你的项目中使用 Global State,你也可以使用一个更好更简单的解决方案,叫做Master-Hook

    第一步: 安装:

    npm i master-hook.
    

    库中已经安装了 Redux 、 react-redux 、 redux-thunk 、 reselect ,您需要按照步骤操作。

    第二步: 创建‘src/hooks.js’文件

    import MasterHook from 'master-hook'
    
    export const useMyHook = MasterHook({
      storage: "myStorage",
      initialState: {
        myName: 'Vanda',
      },
      cache: {
        myName: 10000,
      }
    })
    
    1. 您创建组件并将其导出 (useMyHook)
    2. 设置初始状态(initialState:...)
    3. 设置值需要在毫秒内保持缓存多长时间(缓存:...)

    第 3 步: 将提供者添加到src/index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import App from './App';
    import MasterHook from 'master-hook';
    
    ReactDOM.render(
      <React.StrictMode>
        <MasterHook.Provider>
          <App />
        </MasterHook.Provider>
      </React.StrictMode>,
      document.getElementById('root')
    );
    
    1. 导入 MasterHook
    2. 使用 MasterHook.Provider 包装您的文件

    第 4 步 在src/App.js中使用你的钩子

    import logo from './logo.svg';
    import './App.css';
    import { useMyHook } from './hooks'
    
    function App() {
      const { myName, setMyName } = useMyHook()
    
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>
              My name is {myName}
            </p>
            <a
              onClick={() => setMyName('Boris')}
              className="App-link"
            >
              Set my name to 'Boris'
            </a>
          </header>
        </div>
      );
    }
    
    export default App;
    
    1. 导入你的钩子

    使用MyHook

    1. 声明你的钩子

    const { myName, setMyName } = useMyHook()

    1. 在您的代码中使用它

    {我的名字}

    {()=>setMyName('')}

    删除 href 属性以防止它改变页面。 setMyName 动作是自动创建的。

    无需连接到商店。它已经连接了。

    第 5 步 开始您的项目并享受吧! (npm run start)

    您已连接到 Redux。 myStorage 中的 myName 缓存 10 秒。您可以单击链接,重新加载页面并确保它是。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-26
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 2020-10-11
    • 2018-09-19
    • 2020-03-04
    • 1970-01-01
    相关资源
    最近更新 更多