reactjs 使用React Redux更新同一组件的不同示例的状态

pieyvz9o  于 2023-04-29  发布在  React
关注(0)|答案(3)|浏览(178)

我有一个组件的两个示例,我希望它们的行为像切换按钮。如果我单击一个特定的组件示例,其他组件示例应该被取消选择。

下面是我的代码:
store.js:

import { configureStore } from '@reduxjs/toolkit'
import boxReducer from './slices/boxSlice'

export default configureStore({
  reducer: {
    box:boxReducer
  }
})

boxSlice.js:

export const boxSlice = createSlice({
  name: "box",
  initialState: {
      selected: false,
  },
  reducers: {
    select: (state) => {
    state.selected=true;
    },
    deselect: (state) => {
        state.selected=false;
    },
  },
});

export const { select, deselect } = boxSlice.actions;
export default boxSlice.reducer;

Box.js:

export function Box(){
  const selectedStatus = useSelector((state) => state.box.selected)
  const dispatch = useDispatch()
  const [status, setStatus] = useState("Unselected")

  const onSelect = (e) => {
    dispatch(select());
    if (selectedStatus) {
      setStatus("Selected")
      dispatch(deselect());
    } else {
      setStatus("Unselected");
    }
  }

  return (
    <div tabIndex="0" onClick={onSelect} className="box">
      {status}
    </div>
  )
}

这是臭虫。我观察到的是:

  • 第一次单击时,示例不会更新。它得到更新只有在第二次点击
  • 它无法正确切换。两者都保持选中或未选中状态

每当单击组件的一个示例时,如何正确地更新这些示例

czfnxgou

czfnxgou1#

还原状态应该是真理的源泉。我建议给每个盒子组件一个唯一的id,并存储当前选择的盒子id。如果已经选择了相同的框ID,请取消选择框ID,否则,设置为新ID。
示例:
boxSlice.js

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

export const boxSlice = createSlice({
  name: "box",
  initialState: {
    selected: null
  },
  reducers: {
    select: (state, { payload }) => {
      state.selected = state.selected === payload ? null : payload;
    }
  }
});

export const { select } = boxSlice.actions;
export default boxSlice.reducer;

盒子

function Box({ id }) {
  const dispatch = useDispatch();

  const selected = useSelector((state) => state.box.selected);
  const isSelected = selected === id;

  const onSelect = () => {
    dispatch(select(id));
  };

  return (
    <div tabIndex="0" onClick={onSelect} className="box">
      {isSelected ? "Selected" : "Unselected"}
    </div>
  );
}

应用程序

<Box id={1} />
<Box id={2} />

643ylb08

643ylb082#

您可以利用useSelector返回的Redux状态,而不是在组件中维护单独的state
尝试点击下面的“选中”和“未选中”来查看它的工作情况:

export function Box({ inverse }) {
  const selected = useSelector((state) => state.box.selected);
  const dispatch = useDispatch();

  const onSelect = () => {
    if (selected) {
      dispatch(deselect());
    } else {
      dispatch(select());
    }
  };

  const actualSelected = inverse ? !selected : selected;

  return (
    <div tabIndex="0" onClick={onSelect} className="box">
      {actualSelected ? 'Selected' : 'Unselected'}
    </div>
  );
}

<Box />
<Box inverse />

在此之后,您可以有另一个布尔标志(例如。inverse)来知道2个盒子的哪个分量应该被反转。

const { useState } = React;
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createSlice, configureStore } = RTK;

const boxSlice = createSlice({
  name: 'box',
  initialState: {
    selectedId: 0
  },
  reducers: {
    select: (state, action) => {
      state.selectedId = action.payload;
    }
  }
});

const { select } = boxSlice.actions;
const boxReducer = boxSlice.reducer;
const store = configureStore({
  reducer: {
    box: boxReducer
  }
});

const Box = () => {
  // Random generate ID for this box. For React 18+, you can consider using useId() instead
  // Saving in state instead of memo ensures the value will always stay the same
  const [randomId] = useState(() => Math.random());
  const selectedId = useSelector((state) => state.box.selectedId);
  const isSelected = selectedId === randomId;
  const dispatch = useDispatch();

  const onSelect = () => {
    dispatch(select(randomId));
  };

  return (
    <div tabIndex="0" onClick={onSelect} className="box">
      {isSelected ? 'Selected' : 'Unselected'}
    </div>
  );
};

const App = () => (
  <Provider store={store}>
    <Box />
    <Box />
    <Box />
    <Box />
    <Box />
  </Provider>
);

ReactDOM.render(<App />, document.getElementById('react'));
.box {
  padding: 16px 32px;
  border: 1px solid black;
  display: inline-block;
  font-family: sans-serif;
  margin-right: 16px;
  margin-bottom: 16px;
  user-select: none;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/redux@4.2.1/dist/redux.min.js"></script>
<script src="https://unpkg.com/react-redux@7.2.9/dist/react-redux.min.js"></script>
<script src="https://unpkg.com/@reduxjs/toolkit@1.9.5/dist/redux-toolkit.umd.min.js"></script>
<div id="react"></div>
yacmzcpb

yacmzcpb3#

试试这个

export function Box(){
  const selectedStatus = useSelector((state) => state.box.selected)
  const dispatch = useDispatch()
  const [status, setStatus] = useState("Unselected")

  const onSelect = (e) => {
    dispatch(select());
    if (selectedStatus) {
      setStatus("Unselected")
      dispatch(deselect());
    } else {
      setStatus("Selected");
      dispatch(select());
    }
  }

  return (
    <div tabIndex="0" onClick={onSelect} className="box">
      {status}
    </div>
  )
}

相关问题