使用react-redux的三种方式

#创作灵感#

在学习和使用react-redux开发过程中,碰到过不同的react-redux的使用方式,在经过查阅资料和文档后总结了三种react-redux的使用方式,下面分别通过这三种方式来实现redux官方的todos示例

#示例截图#

 

一、使用connect来连接redux store和react组件

完整代码:redux-connect: 使用connect来连接redux store和react组件的方式实现redux官方示例中的todos示例

connect()相关文档:API · Redux

项目目录结构

index.js 

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

// redux
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './store/index'
import { composeWithDevTools } from 'redux-devtools-extension'
const store = createStore(reducer, composeWithDevTools())

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

App.js

import AddTodo from './containers/AddTodo'
import VisibleTodoList from './containers/VisibleTodoList'
import Footer from './components/Footer';
function App() {
  return (
    <div>
      <AddTodo />
      <VisibleTodoList />
      <Footer />
    </div>
  );
}

export default App;

store/action.js

let nextTodoId = 0
export const addTodo = text => ({
  type: 'ADD_TODO',
  id: nextTodoId++,
  text
})

export const toggleTodo = id => ({
  type: 'TOGGLE_TODO',
  id
})

export const setVisibilityFilter = filter => ({
  type: 'SET_VISIBILITY_FILTER',
  filter
})

export const VisibilityFilters = {
  SHOW_ALL: 'SHOW_ALL',
  SHOW_COMPLETED: 'SHOW_COMPLETED',
  SHOW_ACTIVE: 'SHOW_ACTIVE'
}

 store/index.js

import { combineReducers } from "redux";
import todosReducer from './todosReducer'
import visibilityFilterReducer from './visibilityFilterReducer'

export default combineReducers({
  todosReducer,
  visibilityFilterReducer
})

store/todosReducer.js

const todosReducer = (state = [], action) => {
  switch (action.type) { 
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          id: action.id,
          completed: false
        }
      ]
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id)
          ? {...todo, completed: !todo.completed}
          : todo
      )
    default:
      return state
  }
}

export default todosReducer

store/ visibilityFilterReducer.js

import { VisibilityFilters } from './action'

const visibilityFilterReducer = (state = VisibilityFilters.SHOW_ALL, action) => {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

export default visibilityFilterReducer

containers/AddTodo.js

import { connect } from "react-redux";
import { addTodo } from '../store/action'

const AddTodo = ({dispatch}) => {
  let input
  const handleAddTodo = (e) => {
    e.preventDefault()
    if (!input.value.trim()) return
    dispatch(addTodo(input.value))
    input.value = ''
  }
  return (
    <div>
      <form onSubmit={(e)=>handleAddTodo(e)}>
        <input ref={node => input = node} />
        <button type="submit">
          Add Todo
        </button>
      </form>
    </div>
  )
}

export default connect()(AddTodo)

containers/VisibleTodoList.js

  • connect(mapStatetoProps,mapDispatchToProps)(TodoList)会将todos和toggleTodo注入到TodoList的props中
import { connect } from "react-redux";
import TodoList from "../components/TodoList";
import { toggleTodo, VisibilityFilters } from "../store/action";

const getFiltertodos = (todos, filter) => {
  switch (filter) { 
    case VisibilityFilters.SHOW_ALL:
      return todos
    case VisibilityFilters.SHOW_ACTIVE:
      return todos.filter(item => item.completed === false)
    case VisibilityFilters.SHOW_COMPLETED:
      return todos.filter(item => item.completed === true)
    default:
      return todos
  }
}
const mapStateToProps = (state) => {
  return {
    todos: getFiltertodos(state.todosReducer, state.visibilityFilterReducer)
  }
}
const mapDispatchToProps = (dispatch) => ({
  toggleTodo: id => dispatch(toggleTodo(id))
})
  
export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

components/TodoList.js

  • 在ToodList组件中可以从props中把注入的todos, toggleTodo解构出来
import Todo from './Todo'

const TodoList = ({ todos, toggleTodo }) => {
  return (
    <ul>
      {todos.map(todo =>
        <Todo
          key={todo.id}
          {...todo}
          onClick={()=>toggleTodo(todo.id)}
        />
      )}
    </ul>
  )
}

export default TodoList

components/Todo.js

const Todo = ({ onClick, completed, text }) => (
  <li
    onClick={onClick}
    style={{
      textDecoration: completed ? 'line-through' : 'none'
    }}
  >
    {text}
  </li>
)

export default Todo

components/Footer.js

import React from 'react'
import FilterLink from '../containers/FilterLink'
import { VisibilityFilters } from '../store/action'

const Footer = () => (
  <div>
    <span>Show: </span>
    <FilterLink filter={VisibilityFilters.SHOW_ALL}>
      All
    </FilterLink>
    <FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>
      Active
    </FilterLink>
    <FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>
      Completed
    </FilterLink>
  </div>
)

export default Footer

containers/FilterLink.js

import { connect } from 'react-redux'
import { setVisibilityFilter } from '../store/action'
import Link from '../components/Link'

// 第二个参数ownProps为Link组件的props
const mapStateToProps = (state, ownProps) => ({
  active: ownProps.filter === state.visibilityFilterReducer
})

const mapDispatchToProps = (dispatch, ownProps) => ({
  onClick: () => dispatch(setVisibilityFilter(ownProps.filter))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

components/Link.js

import React from 'react'

const Link = ({onClick, active, children}) => (
  <button
    onClick={onClick}
    disabled={active}
    style={{
      marginLeft: '4px',
    }}
  >
    {children}
  </button>
)

export default Link

二、在react Hook下使用redux使用,useSelector,useDispatch替换connect

在这种方式下不在需要使用connect去连接redux store和react组件并注入state和dispatch,可以直接在组件中使用useSelector来获取state、useDispatch获取dispatch

完整代码:redux-hook: 使用useSelector,useDispatch实现redux官方示例中todos示例

项目目录结构

在第一种方式的基础上修改

  1. 把AddTodo组件的封装提出来并删掉container文件夹
  2. 修改App.js和components下的组件

修改如下: 

App.js

import AddTodo from './components/AddTodo'
// import VisibleTodoList from './containers/VisibleTodoList'
import TodoList from './components/TodoList';
import Footer from './components/Footer';
function App() {
  return (
    <div>
      <AddTodo />
      <TodoList />
      <Footer />
    </div>
  );
}

export default App;

 AddTodo.js

import { addTodo } from '../store/action'
import { useDispatch } from 'react-redux'

const AddTodo = () => {
  let input
  const dispatch = useDispatch()
  const handleAddTodo = (e) => {
    e.preventDefault()
    if (!input.value.trim()) return
    dispatch(addTodo(input.value))
    input.value = ''
  }
  return (
    <div>
      <form onSubmit={(e)=>handleAddTodo(e)}>
        <input ref={node => input = node} />
        <button type="submit">
          Add Todo
        </button>
      </form>
    </div>
  )
}

export default AddTodo

TodoList.js

import Todo from './Todo'
import { useSelector, useDispatch } from 'react-redux'
import { toggleTodo } from '../store/action'
import { VisibilityFilters } from '../store/action'

const TodoList = () => {
  const dispatch = useDispatch()
  const todos = useSelector(state => state.todosReducer)
  const filter = useSelector(state => state.visibilityFilterReducer)

  const getFiltertodos = (todos, filter) => {
    switch (filter) { 
      case VisibilityFilters.SHOW_ALL:
        return todos
      case VisibilityFilters.SHOW_ACTIVE:
        return todos.filter(item => item.completed === false)
      case VisibilityFilters.SHOW_COMPLETED:
        return todos.filter(item => item.completed === true)
      default:
        return todos
    }
  }
  const visibilityTodos = getFiltertodos(todos, filter)
  return (
    <ul>
      {visibilityTodos.map(todo =>
        <Todo
          key={todo.id}
          {...todo}
          onClick={()=>dispatch(toggleTodo(todo.id))}
        />
      )}
    </ul>
  )
}

export default TodoList

Footer.js

import React from 'react'
// import FilterLink from '../containers/FilterLink'
import Link from './Link'
import { VisibilityFilters } from '../store/action'

const Footer = () => (
  <div>
    <span>Show: </span>
    <Link filter={VisibilityFilters.SHOW_ALL}>
      All
    </Link>
    <Link filter={VisibilityFilters.SHOW_ACTIVE}>
      Active
    </Link>
    <Link filter={VisibilityFilters.SHOW_COMPLETED}>
      Completed
    </Link>
  </div>
)

export default Footer

Link.js

import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { setVisibilityFilter } from '../store/action'

const Link = ({ children, filter}) => {
  const dispatch = useDispatch()
  const activeFilter = useSelector(state => state.visibilityFilterReducer)
  const active = activeFilter === filter
  return(
    <button
      onClick={()=>dispatch(setVisibilityFilter(filter))}
      disabled={active}
      style={{
        marginLeft: '4px',
      }}
    >
      {children}
    </button>
  )
}

export default Link

三、使用Redux Toolkit

这是官方推荐的方法,编写起来更加容易

官方文档:入门 Redux | Redux 中文官网

完整代码:redux-toolkit: react-redux结合Redux Toolkit实现redux官方示例中todos示例 

  1. 在第二种方法的基础下先下载Redux Toolkit   npm i @reduxjs/toolkit
  2. 修改index.js和store文件夹啊下的js文件

修改如下:

 index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';
import store from './store/index'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

store/index.js

import { configureStore } from '@reduxjs/toolkit'
import todosReducer from './todosReducer'
import visibilityFilterReducer from './visibilityFilterReducer'

const store = configureStore({
  reducer: {
    todos: todosReducer,
    filter: visibilityFilterReducer
  }
})

export default store

store/todosReducer.js

import { createSlice } from "@reduxjs/toolkit"

let nextTodoId = 0
const todosReducer = createSlice({
  name: 'todos',
  // 初始状态
  initialState: {
    todos:[]
  },
  // 修改数据的方法
  reducers: {
    addTodo(state,action){
      state.todos.push({
        text: action.payload,
        id: nextTodoId++,
        completed: false
      })
    },
    toggleTodo(state, action) { 
      const item = state.todos.find(item => item.id === action.payload)
      item.completed = !item.completed
    }
  }
})

export const {addTodo, toggleTodo} =  todosReducer.actions

export default todosReducer.reducer

store/visibilityFilterReducer.js

import { VisibilityFilters } from './filters'
import { createSlice } from "@reduxjs/toolkit"
const filterReducer = createSlice({
  name: 'filter',
  // 初始状态
  initialState: {
    filter: VisibilityFilters.SHOW_ALL
  },
  // 修改数据的方法
  reducers: {
    setFilter(state,action) {
      state.filter = action.payload
    }
  }
})

export const { setFilter } = filterReducer.actions

export default filterReducer.reducer

  • 30
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最新版的 react-redux 使用方法如下: 首先,确保你的项目已经安装了 react-redux 依赖包。你可以使用以下命令安装它: ``` npm install react-redux ``` 或 ``` yarn add react-redux ``` 接下来,你需要创建一个 Redux store。你可以使用 Redux Toolkit 来简化这个过程。首先,导入 `configureStore` 和 `getDefaultMiddleware` 函数: ``` import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; ``` 然后,创建一个 rootReducer 来合并你的所有 reducer: ``` import { combineReducers } from 'redux'; const rootReducer = combineReducers({ // 这里是你的 reducer }); ``` 接着,使用 `configureStore` 函数创建 Redux store。你可以通过传入一个对象来配置 store,例如指定 reducer、middleware 等等。以下是一个示例: ``` const store = configureStore({ reducer: rootReducer, middleware: getDefaultMiddleware() }); ``` 现在,你可以使用 `<Provider>` 组件来将 Redux store 提供给你的整个应用程序。在你的根组件中,导入 `<Provider>` 组件和你的 Redux store,然后将其包裹在应用的最外层: ``` import { Provider } from 'react-redux'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); ``` 通过将 Redux store 提供给整个应用程序,你可以在应用的任何地方使用 `useSelector` 和 `useDispatch` 钩子来访问 Redux store 中的状态和分发 action。例如,在你的组件中,你可以这样使用: ``` import { useSelector, useDispatch } from 'react-redux'; const MyComponent = () => { const counter = useSelector(state => state.counter); const dispatch = useDispatch(); // 使用 counter 和 dispatch }; ``` 这就是最新版的 react-redux使用方法。你可以根据你的具体需求,自定义配置和使用其他相关的 react-redux API。希望对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值