React:Redux 状态在一个效果中更新,但同一组件中的下一个效果是使用状态的先前值

React: Redux state updated in one effect but next effect in same component is using previous value of state

使用 react 16.8.2, hooks API.

Redux 初始状态:

const initialState = {
  name: one,
  count: 1,
}

分量:

function CompTwo(props) {
  useActiveCount(setActiveCount, 2); 
  useEffect(() => {
    // activeCount is still 1
    if(activeCount === 2) {
      setActiveName('two')
    }
  });
}

const mapStateToProps = state => ({
  activeCount: state.count,
});

const mapDispatchToProps = dispatch => ({
  setActiveCount: count => dispatch(updateActiveCount(count)),
  setActiveName: name => dispatch(updateActiveName(name),
});

export default connect(mapStateToProps, mapDispatchToProps)(CompTwo);

useActiveCount:

const useActiveCount = function (setActiveCount, count) {
  useEffect(() => {
    setActiveCount(count);
  })
}

CompTwo 中,如果我在设置活动名称 setActivePage('two') 之前设置计数 useActiveCount(setActiveCount, 2);,我不应该在 activeCount 中获得新值 2 ]道具?

它确实将 activeCount 设置为 2,当我在 dev-tool 控制台中检查 redux logger 中的状态值时,但是在 CompTwouseEffect 代码中,我仍然变老了activeCount 的值即 1.

为什么会这样?

您需要将 activeCount 传递给 useEffect 挂钩,否则它不会在操作完全完成后重新触发挂钩。

function CompTwo({ activeCount, setActiveCount, setActiveName }) {
  useActiveCount(setActiveCount, 2); 
  useEffect(() => {
    if(activeCount === 2) {
      setActiveName('two');
    }
  }, [activeCount]);
}

可运行示例:

// Custom hook

const useActiveCount = (setActiveCount, count) => {
  React.useEffect(
    () => {
      setActiveCount(count);
    }, [count]
  );
};

// Redux types

const SET_ACTIVE_COUNT = "SET_ACTIVE_COUNT";

const SET_ACTIVE_NAME = "SET_ACTIVE_NAME";

// Redux actions

const updateActiveCount = count => ({
  type: SET_ACTIVE_COUNT,
  count,
});

const updateActiveName = name => ({
  type: SET_ACTIVE_NAME,
  name,
});

// Redux Reducer

const reducer = (state = { count: 0 }, action) => {
  switch (action.type) {
    case SET_ACTIVE_COUNT:
      return {
        ...state,
        count: action.count
      };
    case SET_ACTIVE_NAME:
      return {
        ...state,
        name: action.name
      };
    default:
      return state;
  }
};

const store = Redux.createStore(reducer);

// Comp 2

function CompTwo({ activeCount, activeName, setActiveCount, setActiveName }) {
  useActiveCount(setActiveCount, 2);
  React.useEffect(() => {
    console.log(activeCount);
    if (activeCount === 2) {
        console.log('hit');
        setActiveName('Two');
    }
  }, [activeCount]);
  return (
    <React.Fragment>
        <h5>Count: {activeCount}</h5>
        <h5>Name: {activeName}</h5>
    </React.Fragment>
  );
}

const mapStateToProps = state => ({
  activeCount: state.count,
  activeName: state.name,
});

const mapDispatchToProps = dispatch => ({
  setActiveCount: count => dispatch(updateActiveCount(count)),
  setActiveName: name => dispatch(updateActiveName(name)),
});

const Comp = ReactRedux.connect(
  mapStateToProps,
  mapDispatchToProps
)(CompTwo);

// App

const App = () => (
  <ReactRedux.Provider store={store}>
    <Comp />
  </ReactRedux.Provider>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.1/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/6.0.1/react-redux.min.js"></script>
<div id="root"></div>