Redux的UseSelect钩子一直在重新渲染。

问题描述 投票:0回答:1

我创建了三个useSelector钩子,对于第一个钩子,我用OnClick函数调度一个动作来改变其值。当我这样做的时候,我的其他useSelects被重新渲染,即使引用没有改变。有人知道为什么会发生这种情况吗?我相信这是因为我把 console.logs 放在useSelectors里面,每次我点击按钮时都会看到它们被触发。 minedDiamond--------。 是我点击按钮时唯一要改变的值。

Minecraft.js

import React, { useEffect, useCallback } from "react";
import { connect, useSelector, useDispatch, shallowEqual } from "react-redux";
import { mineDiamond, fetchMinecraftItems } from "../redux/diamonds/actions";


const Minecraft = () => {
  const loading = useSelector((state) => {
    console.log("loading output");
    return state.diamond.loading;
  });
  let minedDiamond = useSelector((state) => {
    console.log("diamond output");
    return state.diamond.minedDiamond;
  });
 const names = useSelector((state) => {
    console.log("name rendered");
    let data = state.diamond.minecraftData;
    return data.map((i) => i.name);
  });
  const dispatch = useDispatch();
  const handleClick = () => dispatch(mineDiamond((minedDiamond += 1)));

  useEffect(() => {
    dispatch(fetchMinecraftItems());
  }, []);
  console.log({ loading });
  return (
    <div className="wrapper">
      <div className="wrapper__item">
        <img src="/image/pickaxe.png" alt="diamond" />
        <button onClick={handleClick} type="button" className="wrapper__button">
          Mine
          <span role="img" aria-label="cart">
            🛒
          </span>
        </button>
      </div>
      <div className="wrapper__item">
        <img src="/image/diamond.png" alt="axe" />
        <span className="num">{minedDiamond}</span>
      </div>
      <div className="num">
        {loading ? (
          <p>loading...</p>
        ) : (
          <h1 className="num">{names}</h1>
        )}
      </div>
    </div>
  );
};

export default Minecraft;

动作创作者

import * as Actions from "./actionTypes";
import axios from "axios";

//action creator
export const mineDiamond = (addDiamond) => ({
  type: Actions.MINE_DIAMOND,
  payload: addDiamond,
});

export function fetchMinecraftItems() {
  return function (dispatch) {
    dispatch({ type: Actions.MINECRAFT_DATA_FETCH });
    return fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json())

      .then((json) => {
        dispatch({ type: Actions.MINECRAFT_DATA_SUCCESS, payload: json });
      })
      .catch((err) =>
        dispatch({ type: Actions.MINECRAFT_DATA_FAIL, payload: err })
      );
  };
}


减速器

import * as Actions from "./actionTypes";

//reducer holds initial state
const initialState = {
  minedDiamond: 0,
  minecraftData: [],
  loading: false,
  error: null,
};

//reducer
const diamondReducer = (state = initialState, action) => {
  switch (action.type) {
    case Actions.MINE_DIAMOND:
      return {
        ...state,
        minedDiamond: action.payload,
      };
    case Actions.MINECRAFT_DATA_FETCH:
      return {
        ...state,
        loading: true,
      };
    case Actions.MINECRAFT_DATA_SUCCESS:
      return {
        ...state,
        loading: false,
        minecraftData: action.payload,
      };
    case Actions.MINECRAFT_DATA_FAIL:
      return {
        ...state,
        error: action.payload,
      };
    default:
      return state;
  }
};

export default diamondReducer;

reactjs redux react-redux memoization reselect
1个回答
2
投票

你的问题与 console.log 的使用无关。你能不能包括你的动作创建者和减速器的代码?

假设state.diamond.mincraftdata是一个数组,那么这行代码是

return data.map((i) => i.name);

每次运行选择器时都会创建一个新的数组。根据 react-redux docs:

当一个动作被派发到Redux商店时,只有当选择器的结果与最后的结果不同时,useSelector()才会强制重新渲染。从v7.1.0-alpha.5开始,默认的比较是严格的===参考比较。

© www.soinside.com 2019 - 2024. All rights reserved.