reactjs React,在功能组件中调度后获得更新的状态

ou6hu8tu  于 2023-01-12  发布在  React
关注(0)|答案(4)|浏览(159)

我使用选择器(不必)检索nextStep
我分派someAction,这可以改变我想要做的nextStep,但是nextStep没有用下面的代码更新。

const App = (props) => {
  const dispatch = useDispatch()
  const nextStep = useSelector(getNextStep)

  const handleSubmit = () => {
    dispatch(someAction())      // this can change the nextStep
    dispatch(gotoStep(nextStep))   //  this nextStep is computed before someAction
  }

}

export const getNextStep = (state) => {
  let {step, stepList} = state.my_reduxer
  let index = stepList.indexOf(step) // someAction changes stepList
  let next_step = stepList[index + 1]

  return next_step
}

如何获得gotoStep操作的更新nextStep
--编辑
我可以想到类似下面的内容,但不确定这是否能保证正确的行为

const App = (props) => {
  const dispatch = useDispatch();
  const nextStep = useSelector(getNextStep);
  const [done, setDone] = useState(false);
  const handleSubmit = () => {
    dispatch(someAction()); // this can change the nextStep

    setDone(true);
  };

  useEffect(() => {
    if (done) {
      dipatch(gotoStep(nextStep)); //  nextStep is hopefully updated?
    }
  }, [done]);
};
anauzrmj

anauzrmj1#

someAction可能会更改nextStep,也可能不会更改nextStep,我希望在更新done和可能更新nextStep后前进到nextStep
这段代码保证只有在done发生变化时才能执行下一步,并且不会得到过时的值。

const App = () => {
  const nextStep = useSelector(getNextStep);
  const stepRef = useRef(nextStep);

  const handleSubmit = () => {
    dispatch(someAction());
    setDone(true);
  };

  useEffect(() => {
    if (done) {
      dispatch(gotoStep(stepRef.current));
    }
  }, [done]);

  useEffect(() => {
    stepRef.current = nextStep;
  }, [nextStep]);
};
smdnsysy

smdnsysy2#

假设触发效果的是nextStep本身,因为如果使用done状态,仍然不能保证对象已经被归约

useEffect(() => dipatch(gotoStep(nextStep)), [nextStep]);

如果你不想在初始化渲染时运行这个效果,那么就像下面这样使用

const [ isInit, setIsInit ] = useState(true)
useEffect(() => isInit ? setIsInit(false) : dipatch(gotoStep(nextStep)), [nextStep]);

现在handleSubmit函数只负责调度

const handleSubmit = () => dispatch(someAction()); // this can change the nextStep
93ze6v8z

93ze6v8z3#

感谢大家的讨论@Dennis Vash!
我不确定你的解决方案是否能解决我在评论中提出的问题
这是我的解决方案,我仍然没有明确的书面答案,但感觉更安全与它。(它似乎工作)

const App = (props) => {
  const dispatch = useDispatch();
  const nextStep = useSelector(getNextStep);
  const myStepDone = useSelector(getMyStep);

  const handleSubmit = () => {
    dispatch(someAction()); // this can change the nextStep
    dispatch(updateMyStepDone()); // let's use redux state for done
  };

  useEffect(() => {
    if (myStepDone) {
      dipatch(gotoStep(nextStep)); //  I hope actions I submitted in handleSubmit updates state simulateneously
    }
  }, [myStepDone]);
};
vkc1a9a2

vkc1a9a24#

你可以通过手动调用reducer来获得更新后的状态,这是我能想到的最简单的解决方案:

import React from "react";
import { useReducer } from "react";

function reducer(state, action) {
  if (action.type === "nextState") {
    state += 1;
  } else {
    throw new Error(`Unknown action ${action}`);
  }

  return state;
}

export function App(props) {
  let [state, dispatch] = useReducer(reducer, 0);

  function onClick() {
    // This may update 'state'.
    let action = { type: "nextState" };
    dispatch(action);

    // We can get the updated state by manually calling the reducer.
    let newState = reducer(state, action);
    console.log(`state=${newState}`);
  }

  return (
    <div>
      state={state}<br />
      <button onClick={onClick}>Do stuff</button>
    </div>
  );
}

请注意,我使用React中的新useReducer函数,因为它更容易创建可重现的示例,但相关代码与Redux没有什么不同:

// This may update 'state'.
let action = { type: "nextState" };
dispatch(action);

// We can get the updated state by manually calling the reducer.
newState = reducer(state, action);
console.log(`state=${newState}`);

由于reducer函数不能有副作用,我们可以安全地再次调用它。如果你试图链接多个调用,这确实会变得很糟糕,但这是我能想出的最好的。

相关问题