简体   繁体   中英

React-Redux. After changing state by useDispatch, components not updating by useSelector

I have useSelectors to check if my App component is updating. The first at the beginning of App component and the second one at App return part. By clicking on letters, currendElementId in store is updating with no problem (I checked by Redux DevTools). But useSelectors not updating.

I know that state should update in reducers immutable, but in createSlice we may use mutable code, so that's not my case. (Anyway, I have already tried to make state copy, change it and then send it, but it works same way)

There are my code: store.js

import { configureStore } from "@reduxjs/toolkit";
import pagesReducer from "./../features/Pages/pagesSlice.js";

export default configureStore({
    reducer: {
        pagesInfo: pagesReducer,
    },
})

pageSlice.js

import { createSlice, nanoid } from "@reduxjs/toolkit";

const initialState = {
    currentPage: 0,
    currentElementId: null,
    pages: [ // Pages
        { // Page
            id: nanoid(),
            lines: [
                { // Line
                    id: nanoid(),
                    aligned: "left",
                    content: [
                        { // Symbol
                            id: nanoid(),
                            type: "symbol",
                            symbol: "F",
                            isBold: false,
                            isItalic: false,
                            isUnderlined: false,
                            fontSize: 18,
                            color: "black",
                        },
                        { // Symbol
                            id: nanoid(),
                            type: "symbol",
                            symbol: "o",
                            isBold: false,
                            isItalic: false,
                            isUnderlined: false,
                            fontSize: 18,
                            color: "black",
                        },
                        { // Symbol
                            id: nanoid(),
                            type: "symbol",
                            symbol: "r",
                            isBold: false,
                            isItalic: false,
                            isUnderlined: false,
                            fontSize: 18,
                            color: "black",
                        },
                    ],
                },
                {
                    id: nanoid(),
                    aligned: "left",
                    content: [
                        { // Image
                            id: nanoid(),
                            type: "image",
                            imageSrc: "./img/me and the boys.png",
                            width: 200,
                            height: 200,
                        },
                    ],
                },
            ],
        },
    ],
}

const textSlice = createSlice({
    name: "pagesInfo",
    initialState,
    reducers: {
        changeCurrentElementID(state, action) {
            state.currentElementId = action.payload;
            // return {
            //     ...state,
            //     currentElementId: action.payload,
            // }
        }
    },
})

export const { changeCurrentElementID } = textSlice.actions;
export default textSlice.reducer;

index.js

import React, { useState } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from "./app/store.js";
import { Provider } from 'react-redux';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

App.js

import css from "./App.module.css";
// import BoldingTextButton from "./features/BoldingTextButton/BoldingTextButton.js";
import "./nullStyle.css";
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { changeCurrentElementID } from "./features/Pages/pagesSlice.js";
import EnterImageButton from "./features/Pages/EnterImage/EnterImageButton.js";
import TextSizing from "./features/Pages/TextSizing/TextSizing.js";
import TextDecoration from "./features/Pages/TextDecoration/TextDecoration.js";
import TextAligning from "./features/Pages/TextAligning/TextAligning.js";

function App(props) {
  console.log(useSelector(state => state.currentElementId));

  const dispatch = useDispatch();

  // document.addEventListener("click", event => {
  //   const target = event.target.closest("li")

  //   if (target) {
  //     const elementID = target.getAttribute("elementid");

  //     dispatch(changeCurrentElementID(elementID));
  //   }
  // })

  const changeElementID = event => {
    const target = event.target.closest("li")

    if (target) {
      const elementID = target.getAttribute("elementid");

      dispatch(changeCurrentElementID(elementID));
    }
  }

  const GetPageContent = () => {
    const rawPageLinesContent = useSelector(state => state.pagesInfo.pages[state.pagesInfo.currentPage].lines);
    const currentElementID = useSelector(state => state.currentElementId);

    const completedPageContent = rawPageLinesContent.map(line => {
      return (
        <ul key={line.id} className={css["page-line"]}>
          {
            line.content.map(element => {
              let finalElement;

              if (element.type == "symbol") {
                const style = { fontSize: element.fontSize + "px" }

                finalElement = (
                  <li onClick={changeElementID} key={element.id} elementid={element.id} className={`${css["page-line__item"]} ${css["page-line__symbol"]}`} style={style}>{element.symbol}</li>
                )

                if (currentElementID == element.id) {
                  finalElement = (
                    <input key={element.id} elementid={element.id} maxLength="1" className={`${css["page-line__item"]} ${css["page-line__symbol"]} ${css["page-line__choosen"]}`} style={style} value={element.symbol} />
                  )
                }
              }
              else if (element.type == "image") {
                finalElement = (
                  <li onClick={changeElementID} key={element.id} elementid={element.id} className={`${css["page-line__item"]} ${css["page-line__image"]}`}>
                    <img src={element.imageSrc} width={element.width} height={element.height} alt="image" />
                  </li>
                )
              }
              // else if (element.type == "enter") {
              //   finalElement = (
              //     <li key={element.id} elementid={element.id} className={`${css["page-line__item"]} ${css["page-line__image"]}`}>
              //       <br />
              //     </li>
              //   )
              // }

              return finalElement;
            })
          }
        </ul >
      )
    })

    return completedPageContent;
  }

  return (
    <div className={css["App"]}>
      <header className={`${css['App__header']} ${css['tools']} `}>
        <EnterImageButton />
        <TextSizing />
        <TextDecoration />
        <TextAligning />
        <div>{useSelector(state => state.currentElementId) || 0}</div>
      </header >
      <div className={`${css['App__content']} ${css['pages']} `}>
        <div className={`${css['pages__item']}`} >
          {GetPageContent()}
        </div>
      </div>
    </div >
  );
}

export default App;

Your selector is wrong.

Since you have

export default configureStore({
    reducer: {
        pagesInfo: pagesReducer,
    },
})

your pages slice is mounted as slice.pagesInfo .

So you need to do

useSelector(state => state.pagesInfo.currentElementId)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM