Redux UseSelect挂钩保持重新渲染

时间:2020-05-03 06:48:21

标签: reactjs redux react-redux memoization reselect

我创建了三个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;

1 个答案:

答案 0 :(得分:2)

您的问题与console.log的使用无关。 您能否为动作创建者和还原者添加代码?

假设state.diamond.mincraftdata是一个数组,一行

return data.map((i) => i.name);
每次运行选择器时,

都会创建一个新数组。按照react-redux docs

当一个动作被分派给Redux的商店,useSelector()只迫使如果选择结果似乎比最后的结果不同重新绘制。从v7.1.0-alpha.5开始,默认比较是严格的===参考比较。