考虑以下两种异径管:
const reducer = (state = initialState, action) => {
switch(action.type){
case 'changeName' :
return { ...state, name: action.name }
default:
return state
}
}
还有:
const reducer = (state = initialState, action) => {
switch(action.type){
case 'changeName' :
state.name = action.name
return { ...state }
default:
return state
}
}
假设我们有一个react组件,它有以下钩子:
const reduxState = useSelector(state=>state)
const [toggle,setToggle] = useState(false)
React.useEffect(() => {
const name = toggle?'Joe':'Bob'
dispatch({type: 'changeName', name}));
console.log('name is:', name, 'name in redux is:', reduxState.name)
}, [toggle]);
假设这是一个在onClick上更改'toggle'的组件。如果我们使用第一个reducer,我们会得到以下输出:
name is: Joe name in redux is: Bob
或
name is: Bob name in redux is: Joe
这是因为组件必须重新呈现才能从redux获得更新的值。但是,如果我需要在同一个useEffect挂钩中从redux获得更新的值呢?我知道这是一个普通的例子,因为我在redux中设置它之前就知道它的名称。但假设我们从api中获取数据,我需要在同一个钩子中立即得到更新后的值,第二个reducer似乎解决了这个问题。它会打印:
name is: Joe name in redux is: Joe
或
name is: Bob name in redux is: Bob
但是,它是通过在发出具有更新状态的新对象之前直接更新redux状态来实现这一点的。(redux使用一个浅层比较来查看组件是否应该被重新渲染)然而,在第二个reducer中,我们实际上发出了一个全新的对象,但我们只是改变了之前的状态,以便立即更新值。
无论如何,我的问题是,这是否违反了我不知道的任何其他规则?实现第二个缩减器是否有任何错误?对我来说,这似乎是一个升级,因为我们在重新渲染之前和之后都得到了更新的值。
2条答案
按热度按时间9jyewag01#
第二个减速器正在做你想要的事情,因为它是直接操纵状态,这是一个非常糟糕的做法。
不要直接操作状态
现在我们来讨论一个问题,如果你想在同一个useEffect中设置一个状态,并且想在同一个useEffect中返回状态,你可以直接使用数据,而不需要从状态中获取数据。
考虑到您的示例,理想的实现应该是:
虽然你说你需要在相同的useEffect中使用数据,但要做到这一点,你可以直接使用变量。redux状态无论如何都会得到更新,在此之前,你可以使用在分派中使用的相同变量。
1mrurvl12#
我刚才也遇到了同样的问题,我的设置是:
CachingXProvider
:我用它来请求某个react组件中的X的值,如果它已经被获取并存储在我的state中,我将它 Package 在Loadable中返回,state = Loaded。否则,我返回一个Loadable,state = Loading,在我的state中缓存这个正在加载的对象,并发出API请求以获取数据(在响应时,更新state中该高速缓存)。我遇到了一个问题,在一个单一的呈现中,一个React组件会两次从缓存数据提供者请求一段数据。第二次请求会再次发出API请求,因为即使第一次请求调度了一个动作来更新redux状态,以记住我们已经请求了该项的事实,这意味该高速缓存将在第二次请求时丢失,并且将进行另一个API调用。
目前为止,我的解决方案是:让我的缓存数据提供程序保留它自己的静态项列表,这些项是它第一次从API请求的。如果在提供程序的生命周期中再次请求任何这样的项,则从该列表提供它。