Состояние React Redux не может повторно передать компонент, и состояние НЕ ОПРЕДЕЛЕНО

#reactjs #redux

Вопрос:

Есть некоторые проблемы с состоянием в Redux. Я хочу изменить цвет компонента с обновлением состояния. Но государство в TargetList.js имеет ошибку: Ошибка типа: Не удается прочитать свойство «включает» неопределенного.

Файл редуктора является:

 import {
  SENSOR_HI,
  SENSOR_UNHI,
} from "redux/actionTypes";
const initialState = {
  title: "",
  text: "",
  detailedList: "hide",
};

const Reducer = (state = initialState, action) => {
  switch (action.type) {
    case SENSOR_HI:
      return {
        ...state,
        sensorarray: action.data,
      };
    case SENSOR_UNHI:
      return {
        ...state,
        sensorarray: [],
      };
    case FILTER_TAGS_CHANGED:
      return {
        ...state,
        filterTags: action.data,
      };
    default:
      return state;
  }
};

export default Reducer;
 

И в TargetList.js является:

 import "assets/scss/global.scss";
import moment from "jalali-moment";
import React, { useState, useEffect, useRef, memo } from "react";
import { OverlayTrigger, Tooltip } from "react-bootstrap";
import { GiMovementSensor, GiRadarSweep } from "react-icons/gi";
import { MdDescription, MdSignalWifiOff,MdNetworkWifi } from "react-icons/md";
import { connect } from "react-redux";
import ToggleButton from "react-switch";
import socketConn from "sockets";
import "./Leaflet.scss";
import classes from "./TargetsList.module.scss";
import { targetTypes, targetsIconsHandlerImage } from "helpers/icons";
import { BackButton } from "assets/js/Icons";
import ReactDOMServer from "react-dom/server";

let TEMP_TARGETS = [];
let counter = 0;
let now = new Date();


const TargetsList = memo((props) => {

  const [sensorFiltersSelected, setSensorFiltersSelected] = useState([]);
  const [sensorFiltersSelectedIds, setSensorFiltersSelectedIds] = useState([]);
  const [sensorSelected, setSensorSelected] = useState(null);
  const [targetFiltersSelected, setTargetFiltersSelected] = useState([]);
  const [hi, sethi] = useState(false);


  let filterType = (sensors) => {
    if (sensorFiltersSelected.length == 0) {
      return sensors;
    } else {
      let ids = sensorFiltersSelected.map((s) => s["_id"]);
      return sensors.filter((s) => ids.includes(s.sensorType["_id"]));
    }
  };

  let filterTextSensors = (sensors) => {
    return sensors.filter((s) => s.latinName.includes(searchInput));
  };

  let toggleFilter = (sensor) => {
    let filters = sensorFiltersSelected;
    let ids = filters.map((f) => f["_id"]);
    if (filters.length amp;amp; ids.includes(sensor["_id"])) {
      filters = filters.filter((f) => f["_id"] != sensor["_id"]);
    } else {
      filters.push(sensor);
    }
    props.dispatch({
      type: "FILTER_TAGS_CHANGED",
      data: [...filters],
    });
    setSensorFiltersSelected(filters);
    setSensorFiltersSelectedIds(filters.map(s=>s.latinName))
    
    props.dispatch({
      type: "SENSOR_HI",
      data: [filters.map(s=>s.latinName)],
    });
  };

  return (
    <div>
      <div
        className="container"
        style={{
          padding: 0,
        }}
      >
                    <div className="rowx my-2 flex-wrap">
                  {props.sensors amp;amp; props.sensors.length
                    ? filterTextSensors(props.sensors).map(
                        (s, sensorTypeIndex) => (
                          <div
                              key={s._id}
/////////////////////////////////////// Here is Error  ///////////////////////////////////////////////
                              className={`cursor-pointer badge badge-pill m-1 ${props.sensorarray.includes(s.latinName) ? `badge-success` : `badge-light`}`}
                            onClick={() => {
                              showLogsSensor(s)
                              toggleFilter(s);
                            }}
                          >
                            {s.persianName}
                          </div>
                        )
                      )
                    : ""}
                </div>


});

const mapStateToProps = (state) => {
  return {
    sensorarray: state.sensorarray,
  };
};
export default connect(mapStateToProps)(TargetsList);
 

И в Drawer.js является ли состояние изменения, которое должно изменить цвет в TargetList.js.
Drawer.js:

 import React from "react";
import clsx from "clsx";
import {makeStyles} from "@material-ui/core/styles";
import Drawer from "@material-ui/core/Drawer";
import {connect} from "react-redux";
import "assets/scss/global.scss";
import "./style.scss";
import socketConn from "sockets";
import moment from "jalali-moment";
import {MdSave} from "react-icons/md";
import axios from "config.js";

const useStyles = makeStyles({
    fullList: {
        width: "auto",
    },
});

function BottomDrawer(props) {
    const classes = useStyles();
    const [tab, setTab] = React.useState("sensors");
    const [state, setState] = React.useState({bottom: false});
    const [type, setType] = React.useState(null);
    const [info, setInfo] = React.useState(null);
    const [logs, setLogs] = React.useState([]);

    const toggleDrawer = (anchor, open) => {
        setState({
            ...state,
            [anchor]: open,
        });

        // stop receiving target logs
        targetsLogAPIHandler(false);
    };
    const sensorunhi = () => {

        props.dispatch({
            type: "SENSOR_UNHI",
           
          });

    };

    let setLogSocket = (type, info) => {
        setLogs([]);
        if (type === "target") {
            targetsLogAPIHandler(true, info);
        }

        if (type === "sensor") {
            sensorsLogAPIHandler(info);
        }
    };

    // handler for API request to NodeJS to get logs of specific target (! ! ! requestMode => {true: when you want to START coming logs | false: when you want to STOP coming logs})
    const targetsLogAPIHandler = async (requestMode, info) => {
        try {
            const userId = localStorage.getItem('user_id');
            socketConn().removeAllListeners("show_specific_target_log");

            const {data} = await axios.post(`/targets/log/${userId}`, {
                requestMode,
                unique_id: info ? info.unique_id : undefined
            });

            socketConn().on("show_specific_target_log", targetLogs => {
                setLogs((prev) => {
                    return [targetLogs, ...prev].filter((s, index) => index < 500);
                });
            });
        } catch (err) {
            console.log(err);
        }
    };

    // handler for API request to NodeJS to get logs of specific sensor
    const sensorsLogAPIHandler = async info => {
        try {
            socketConn().removeAllListeners("sensor_moment_log");

            let userId = localStorage.getItem("user_id");

            const logs = await axios.post(`sensors/sensors/logs`, {topic: info.latinName, userId});

            socketConn().on("sensor_moment_log", (data) => {
                let enc = new TextDecoder("utf-8");
                let decoded = enc.decode(data.result.content);
                decoded = JSON.parse(decoded);
                setLogs((prev) => {
                    return [decoded, ...prev].filter((s, index) => index < 500);
                });
            });
            socketConn().on("sensor_moment_log_error", (data) => {
                console.log(data);
            });
        } catch (err) {
            console.log(err);
        }
    };

    React.useEffect(() => {
        setTab((prev) => {
            if (prev != props.selectedTab) {
                socketConn().removeAllListeners("sensor_moment_log");
                socketConn().removeAllListeners("show_specific_target_log");
                setLogs([]);
                return props.selectedTab;
            }
            return prev;
        });
    }, [props.selectedTab]);

    React.useEffect(() => {
        if (props.showLogs amp;amp; state["bottom"] == false) {
            toggleDrawer("bottom", true);
        }
    }, [props.showLogs]);

    React.useEffect(() => {
        if (props.logInfo amp;amp; props.logType) {
            if (info != null) {
                if (
                    type != props.logType ||
                    info.Identification   info.sensorName !=
                    props.logInfo.Identification   props.logInfo.sensorName
                ) {
                    setType(props.logType);
                    setInfo(props.logInfo);
                    setLogSocket(props.logType, props.logInfo);
                }
            } else {
                setType(props.logType);
                setInfo(props.logInfo);
                setLogSocket(props.logType, props.logInfo);
            }
        }
    }, [props.logInfo, props.logType]);

    const list = anchor => (
        <div className={clsx(classes.list, {[classes.fullList]: anchor === "bottom",})} role="presentation">
            <div className="log-container p-4">
                     <React.Fragment>
                       
                       <div className="rowx log-headers mb-3">
                            <div className="colx log-header font-weight-bold">نام سنسور</div>
                            <div className="colx log-header font-weight-bold">نوع هدف</div>
                            <div className="colx log-header font-weight-bold">طول</div>
                            <div className="colx log-header font-weight-bold">عرض</div>
                            <div className="colx log-header font-weight-bold">ارتفاع</div>
                        </div>
                        <div className="log-elements">
                            {logs amp;amp;
                            logs.length amp;amp;
                            logs.map((log, index) => (
                                <div className="rowx log-element mb-2" key={index}>
                                    <div className="colx log-text">{log amp;amp; log[0] amp;amp; log[0].sensorName}</div>
                                    <div className="colx log-text">{log amp;amp; log[0] amp;amp; log[0].sensorType}</div>
                                    <div className="colx log-text">{log amp;amp; log[0] amp;amp; log[0].longitude}</div>
                                    <div className="colx log-text">{log amp;amp; log[0] amp;amp; log[0].latitude}</div>
                                    <div className="colx log-text">{log amp;amp; log[0] amp;amp; log[0].altitude}</div>
                                </div>
                            ))}
                        </div>
                    </React.Fragment>
                )}
            </div>
        </div>
    );

    return (
        <div>
            <React.Fragment>
                <Drawer
                    classes={{root: "drawer-root"}}
                    ModalProps={{hideBackdrop: true}}
                    anchor="bottom"
                    open={state["bottom"]}
                    onClose={() => {
                        toggleDrawer("bottom", false);
                        sensorunhi(); /////////////////// CHANGE REDUX STATE
                    }}
                >
                    {list("bottom")}
                </Drawer>
            </React.Fragment>
        </div>
    );
}

const mapStateToProps = (state) => {
    return {
        sensorarray: state.sensorarray,
    };
};
export default connect(mapStateToProps)(BottomDrawer);
 

Другими словами, я хочу изменить цветовую составляющую TargetList.js путем изменения состояния в Drawer.js.

Комментарии:

1. Вы не должны использовать memo , так как ваш компонент имеет состояние.

2. Измените свое mapStateToProps на sensorarray: state.sensorarray || [] , и у вас не будет undefined .