REDUX. I cant understand how to connect a component defined as a class extending React.Component in order to read the store

為{幸葍}努か 提交于 2021-01-29 20:16:41

问题


First of all, ive read this question React-redux connect() cannot wrap component defined as a class extending React.Component But im still unable to uderstand it since the connect is being done in some kind of upper level, but I dont understand that phase.

This is my current structure:

reduxStore.js

import { createStore } from "redux";
import rootReducer from "../reducers/index";

const store = createStore(rootReducer);

export default store;

action-types.js

export const RENDER_LAYOUT_ELEMENT = "REDER_LAYOUT_ELEMENT"

reduxActions.js

import {RENDER_LAYOUT_ELEMENT} from "../constants/action-types"

export function renderLayoutElement(payload){
    return {type: RENDER_LAYOUT_ELEMENT}
};

reduxReducers.js

import {RENDER_LAYOUT_ELEMENT} from "../constants/action-types"

const initialState = {
    renderedEl: {
        heimdall: false,
        skadi: false,
        mercator: false
    }
}

function renderedElReducer(state = initialState, action){
    if(action.type === RENDER_LAYOUT_ELEMENT){
        return Object.assign({},state,{
            renderedEl: state.renderedEl.concat(action.payload)
        })
    }
    return state
}

export default renderedElReducer;

Now what I want is, to read the renderedEl initialState in a component that I have. Per my understanding, i need to connect that component, to the store and then with a mapStateToProps it would read the global state (the store)

So i go to my component and try to connect it, but I dont understand where to do it.

The component is big, but basically Im trying to stop using the state of renderedEl, to read it from the store. The state im currnetly using is located in the constructor, it should dissapear because it will now be read from the store.

And in the render, the conditional parts of the style, now wont be set based on the states, but based on the store. I was going to do all that, but problem is, right now im stuck with how to connect this component to the store. All the tutorials I have seen are connected with some sort of functioncal componentes and not class componentes

  import React, { Component, useState } from "react";
import brand from "../images/valhallaNaranja.png";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

import { faArrowAltCircleLeft, faArrowAltCircleRight, faUser } from '@fortawesome/free-regular-svg-icons'
import { faColumns } from '@fortawesome/free-solid-svg-icons'
import './css/Sidebar.css'
import { isAdmin } from "../services/userCheck.js"

//select
const mapStateToProps = state => {
    return { renderedEl: state.renderedEl }
}

export default class SideBar extends Component {
    constructor(props) {
        super(props);
        this.state = {
            retracted: this.props.retracted,
            isAdmin: false,
            isHovering: false,
            //THIS STATE IS WHAT IM TRYING TO REPLACE BY READING FROM THE STORE
            renderedEl: {
                heimdall: false,
                skadi: false,
                mercator: false
            }
        }

        this.hoverTrue = this.hoverTrue.bind(this);
        this.hoverFalse = this.hoverFalse.bind(this);
    }



    componentDidMount() {
        if (isAdmin()) {
            this.setState({
                isAdmin: true
            })
        }
    }

    componentDidUpdate() {
        if (this.state.retracted != this.props.retracted) {
            this.setState({
                retracted: this.props.retracted
            })
        }
    }

    renderEl = (el) => {
        var elementName = el.target.getAttribute('id');
        var renderedElements = this.state.renderedEl;

        for (let key in renderedElements) {
            if (key == elementName) {
                renderedElements[key] = true
            }
        }
        this.setState({
            renderEl: renderedElements
        })
    }

    hoverTrue() {
        this.setState({
            isHovering: true
        })
    }

    hoverFalse() {
        this.setState({
            isHovering: false
        })
    }

    render() {

        let navbar_brand = this.state.retracted ? "navbar-brand-retracted" : "navbar-brand";
        let img_redie = this.state.retracted ? "img-redie-retracted" : "img-redie";
        let home_icon = this.state.retracted ? "divicon homeicon-retracted" : "divicon homeicon";
        let register_icon = this.state.retracted ? "divicon divicon2 registericon-retracted" : "divicon divicon2 registericon";
        let expand_icon = this.state.retracted ? "divicon-no-hover divicon2 expandicon-retracted" : "divicon divicon2 expandicon";

    //THOSE STATES WILL BE READ NOW FROM THE STORE
        let skadiRendered = this.state.renderedEl.skadi ? "bubbletext bubbletext-rendered" : "bubbletext";
        let heimdallRendered = this.state.renderedEl.heimdall ? "bubbletext bubbletext-rendered" : "bubbletext";
        let mercatorRendered = this.state.renderedEl.mercator ? "bubbletext bubbletext-rendered" : "bubbletext";

        let layoutAppVisualSelector = this.props.history.location.pathname == "/layout" ? "divicon divicon2 expandicon divicon-layout" : "divicon divicon2 expandicon";
        return (
            <div id="sidebar" className={this.state.retracted ? 'sidebar-retracted' : 'sidebar-expanded'}>
                <div /*routerLink=""*/ className={navbar_brand}>
                    <img alt="Reddie" src={brand} width="60" height="60" className={img_redie} />
                </div>

                <ul className="nav nav3 navbar-nav">
                    <li>
                        {/* Home icon */}
                        <div className={home_icon} onClick={() => this.props.history.push('/')}>
                            <svg className="svgicon-sidebar" viewBox="0 0 14 14" >
                                <path d="M13.9 5.7L7.2.8c-.1-.1-.3-.1-.4 0L.1 5.7c-.1.1-.1.3 0 .5s.3.2.5.1L7 1.6l6.4 4.7c.1 0 .1.1.2.1s.2-.1.3-.1c.1-.3.1-.5 0-.6" />
                                <path d="M12.1 6.4c-.2 0-.4.2-.4.4v5.8H8.8V9.4c0-1-.8-1.8-1.8-1.8s-1.8.8-1.8 1.8v3.2H2.3V6.7c0-.2-.2-.4-.4-.4s-.4.2-.4.4v6.2c0 .2.2.4.4.4h3.6c.2 0 .3-.1.4-.3V9.4c0-.6.5-1.1 1.1-1.1.6 0 1.1.5 1.1 1.1v3.5c0 .2.2.3.4.3h3.6c.2 0 .4-.2.4-.4V6.7c0-.2-.2-.3-.4-.3" />
                            </svg>
                        </div>
                    </li>

                    {this.state.isAdmin ? <li>
                        <div className={register_icon} onClick={() => this.props.history.push('/admin')}>
                            <FontAwesomeIcon className="registerIcon" icon={faUser} />
                        </div>
                    </li> : null}


                    {(this.props.history.location.pathname != "/layout") && (this.props.history.location.pathname != "/skadi") && (this.props.history.location.pathname != "/heimdall") && (this.props.history.location.pathname != "/mercator") ? null : <li>
                        <div className={layoutAppVisualSelector} onMouseEnter={this.hoverTrue}
                            onMouseLeave={this.hoverFalse} >
                            <FontAwesomeIcon className="registerIcon" icon={faColumns} onClick={() => this.props.history.push({ pathname: '/layout', state: { comeFrom: this.props.history.location.pathname } })} />
                            {(this.state.isHovering && this.props.history.location.pathname == "/layout") ? <div className="speech-bubble" onMouseLeave={this.hoverFalse}
                                onMouseEnter={this.hoverTrue}>
                                <span id="heimdall" className={heimdallRendered} onClick={(el) => this.renderEl(el)}>Heimdall</span> <br /> <span className={skadiRendered} id="skadi" onClick={(el) => this.renderEl(el)}>Skadi</span> <br /> <span id="mercator" className={mercatorRendered} onClick={(el) => this.renderEl(el)}>Mercator</span>
                            </div> : null}

                        </div>

                    </li>}

                    {(this.state.retracted) || ((this.props.history.location.pathname == "/") || (this.props.history.location.pathname == "/register")) || (this.props.history.location.pathname == "/admin") || (this.props.history.location.pathname == "/layout") ? null : <li>
                        <div className="divicon divicon2 expandicon " onClick={this.props.retract}>
                            <FontAwesomeIcon className="registerIcon" icon={faArrowAltCircleLeft} />
                        </div>
                    </li>}



                </ul>

                {this.state.retracted ? <div className="expandicon-retracted-container"> <FontAwesomeIcon className="expandicon-retracted" icon={faArrowAltCircleRight} onClick={this.props.unretract} /> </div> : null}

            </div>

        )
    }
}

How would I go about connecting that component?


回答1:


First you need to wrap a root component (most recommended index.js or App.js...) with redux Provider


  import { Provider } from 'react-redux'

 <Provider store={store}>
    <App />
</Provider>

After so, store is provided for all parts that under this , and can be connected like that


   import { connect } from 'react-redux'

   const mapStateToProps = state => {
    return { renderedEl: state.renderedEl }
   }

  class SideBar extends Component {
      componentDidMount() {
         console.log(this.props.renderedEL)
     }
   }

 export default connect(mapStateToProps)(SideBar)

As for your action, dispatch the action towards the reducer


export function renderLayoutElement(payload){
   return dispatch => dispatch({type: RENDER_LAYOUT_ELEMENT})
 }




回答2:


do only export class SideBar [...] for testing purposes, but export default connect(mapStateToProps)(SideBar) which connects your component to redux state and assigns reduced state to props.

Edit: The documentation you're looking for is here.



来源:https://stackoverflow.com/questions/61386044/redux-i-cant-understand-how-to-connect-a-component-defined-as-a-class-extending

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!