在 React 项目中添加 Redux

IT技术 javascript reactjs react-native redux
2021-05-09 01:58:41

在 React 项目中添加 redux(Refactor a simple project with Redux)

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

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

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,因为它是一个最好的做法,当你被迫使用this.state.setState

现在,这个Redux 的实现是什么?

2个回答

首先,您需要通过reduxreact-redux安装到您的项目中npmyarn

您只需使用一行代码即可安装它们:

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
}

动作是从组件分派到 redux 以store通过 reducer更改(状态)的简单函数

所以我们应该改变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(在 switch 中)必须单独返回状态。在返回状态中使用 ...state 意味着如果 initialState 将来会发生变化,这些情况将正常工作(在本例中没有必要)。

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

和最后一个新文件store.js

import {createStore} from "redux";
import reducer from './reducer'

const store = createStore(reducer);

export default store;

现在我们应该将这个 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组件并将传播storeAppCounterApp以及所有其他子组件。

最后,更改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);

我们正在使用increment&decrement动作将动作分派到 redux。

state被删除,而不是状态中,我们创建一个特殊的功能mapStateToProps' and useconnect`的状态连接组件的props。

大功告成!

如果你需要在你的项目中使用全局状态,你也可以使用一个更好更简单的解决方案叫做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. 导入你的钩子

使用我的钩子

  1. 声明你的钩子

const { myName, setMyName } = useMyHook()

  1. 在您的代码中使用它

{我的名字}

{()=>setMyName('')}

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

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

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

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