Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use redux-toolkit createSlice with React class components

I've started using the redux-toolkit slicers in functional components, (example from react-redux example)

slicer:

export const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    value: 0,
  },
  reducers: {
    increment: state => {
      state.value += 1;
    },
    decrement: state => {
      state.value -= 1;
    },
    incrementByAmount: (state, action) => {
      state.value += action.payload;
    },
  },
});

use in component:

const count = useSelector(selectCount);
const dispatch = useDispatch();

return (
  <button
    className={styles.button}
    aria-label="Increment value"
    onClick={() => dispatch(increment())}
  >
)

my question is how can I use this slicer in the class component since I cant use hooks inside them. I've tried using connect (from redux) but I can't find a way to "stitch" the actions and selectors from the slicer to my component. I couldn't find any documentation on this as well.

like image 693
guy dadon Avatar asked Feb 19 '21 12:02

guy dadon


People also ask

Can we use Redux with React class component?

Redux is a library that allows a React app to create a global state object that can be used in any component across the app by consuming the state object.

What is the use of createSlice in Redux toolkit?

A function that accepts an initial state, an object of reducer functions, and a "slice name", and automatically generates action creators and action types that correspond to the reducers and state. This API is the standard approach for writing Redux logic.

Can we use Redux hooks in class component?

You can't use Hooks inside a class component, but you can definitely mix classes and function components with Hooks in a single tree.

What is createslice() function in Redux?

It also helps you organize all of your Redux-related logic for a given slice into a single file. What is createSlice? It’s a function that deals with everything you need for each slice, do you remember using createAction and createReducer manually?

How to use slice in React-Redux?

Use slice the files where you want to use. In my case, I want to use Menu.tsx and Header.tsx, so I put my slice inside these two files. When you want to use these slices, you should use dispatch, in my case I used useDispatch hook in react-redux.

What is a reducer object in Redux?

An object containing Redux "case reducer" functions (functions intended to handle a specific action type, equivalent to a single case statement in a switch). The keys in the object will be used to generate string action type constants, and these will show up in the Redux DevTools Extension when they are dispatched.

What is Redux and why should you use it?

##Why Redux (Quickly)? Redux is a state management tool that helps you control and update your applications state more efficiently. Redux itself is a standalone library which means it’s framework agnostic. You can use it with any framework but it’s usually used with React. Why should you use it?


1 Answers

Class vs. function components and redux-toolkit vs "vanilla" redux are two independent decisions that don't have any impact on each other. (Though you should be aware that function components and hooks are recommended over class components for everything React).

I've tried using connect (from redux) but I can't find a way to "stitch" the actions and selectors from the slicer to my component.

How do the docs "stitch" the actions and selectors when using useDispatch and useSelector? Do that, but with the connect higher-order component instead.

The increment() function in the docs example that you posted doesn't just magically exist, it needs to be imported from the slice. You can export the entire actions object and use actions.increment but you usually see the actions exported as individual variables.

From the docs:

Most of the time, you'll probably want to use ES6 destructuring syntax to pull out the action creator functions as variables, and possibly the reducer as well:

Your slice file might look like this:

const counterSlice = createSlice( /* same as before */ );

// destructure actions and reducer from the slice (or you can access as counterSlice.actions)
const { actions, reducer } = counterSlice;

// export individual action creator functions
export const { increment, decrement, incrementByAmount } = actions;

// often the reducer is a default export, but that doesn't matter
export default reducer;

The first argument of connect is mapStateToProps, where you use selectors (either inline arrow functions state => state.something or selector functions that you import) to create an object of props from the state. That might look like:

const mapStateToProps = (state) => ({
  count: state.counter.value
});

The second argument mapDispatchToProps is optional. If you pass an object with your action creators, your component will receive versions of those action creators that are already bound to dispatch. You would be able to call this.props.increment() directly rather than this.props.dispatch(increment()). You will see this syntax commonly used in tutorials with connect.

import React from "react";
import { connect } from "react-redux";
import { increment, decrement } from "./counterSlice";

class MyComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Count is {this.props.count}</h1>
        <button onClick={() => this.props.increment()}>
          Increment
        </button>
        <button onClick={() => this.props.decrement()}>
          Decrement
        </button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  count: state.counter.value
});

const mapDispatchToProps = { increment, decrement };

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);

If you leave off the mapDispatchToProps argument entirely, your component receives the raw dispatch function. You would call the dispatch on you imported action creators like this.props.dispatch(increment()). This syntax is more similar to how useDispatch is used. Both connect and useDispatch give you access to the dispatch function and you can call that function with an action that you create from an action creator function like increment() or decrement().

import React from "react";
import { connect } from "react-redux";
import { increment, decrement } from "./counterSlice";

class MyComponent extends React.Component {
  render() {
    return (
      <div>
        <h1>Count is {this.props.count}</h1>
        <button onClick={() => this.props.dispatch(increment())}>
          Increment
        </button>
        <button onClick={() => this.props.dispatch(decrement())}>
          Decrement
        </button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  count: state.counter.value
});

export default connect(mapStateToProps)(MyComponent);

Complete CodeSandbox

like image 143
Linda Paiste Avatar answered Oct 24 '22 00:10

Linda Paiste