我一直在追赶React Hooks潮流,并决定将React Native应用程序组合在一起,以尝试提供完整的redux / global状态实现。我一直在关注一些有关如何执行此操作的文章,但是我确实有一些疑问。
我了解useState
和useReducer
的概念,但是我却迷恋于Context
方面。
第一个问题:在不需要使用道具的情况下将状态对象传递到树上的最佳方法是什么?这就是我到目前为止所掌握的。通常,如果没有导航功能,您将有DispatchContext
的子组件可以接收道具。但是因为我有导航功能,所以我真的不想将状态传递给树。我觉得这违背了Context的目的,总的来说是钩子。我已经看到了value={dispatch}
是value={{somePieceOfState}}
的某些地方。如何将状态和调度都传递到组件树中?
import React, { useReducer } from 'react';
import Navigation from './Navigation';
import { DispatchContext } from './Context';
import { countReducer } from './reducers';
const App = () => {
const [count, dispatchCount] = useReducer(countReducer, 0);
const dispatch = action => [dispatchCount].forEach(fn => fn(action)); //provides one dispatch for the entire component tree
const state = {
count,
//other pieces of state go here
}
return (
<DispatchContext.Provider value={dispatch}>
<Navigation />
// <ChildComponent someStateProp={count} /> normal way to pass down props
</DispatchContext.Provider>
);
};
export default App;
第二个问题:做动作和动作创建者的最佳方法是什么?这可能可以与第一个问题一起回答。这是我的导航附件。
import React, { useContext } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { DispatchContext } from './Context';
import { countUp, countDown } from './actions';
const Comp1 = () => {
const dispatch = useContext(DispatchContext);
return (
<View>
<TouchableOpacity
onPress={() => dispatch(countUp)}
>
<Text>Up</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => dispatch(countDown)}
>
<Text>Down</Text>
</TouchableOpacity>
</View>
);
};
export default Comp1;
与之关联的动作:
import {
COUNT_UP,
COUNT_DOWN
} from './types';
export const countUp = () => {
return {
type: COUNT_UP
};
};
export const countDown = () => {
return {
type: COUNT_DOWN
};
};
还有减速器:
import {
COUNT_UP,
COUNT_DOWN
} from '../actions/types';
export const countReducer = (state, action) => {
console.log(action);
switch (action) {
case COUNT_UP:
return state + 1;
case COUNT_DOWN:
return state - 1;
default:
return state;
}
};
我知道动作和调度以及所有有效的方法,因为我在减速器中console.log()
并得到了响应。但是当我console.log(action)
时,它表明它是函数,是动作本身而不是类型。如果我console.log(action.type)
,则未定义。我在这里做错了什么?
最后一个问题:这是一种用于复杂状态管理的合理方法吗?我知道useEffect()
之类的东西,但是从任何有钩子经验的人那里都很好吗?进行API调用和位置跟踪以及类似的操作?这是一种可扩展的方法吗?基本上,我要问的是,我不想深入了解这一点,而不必将所有内容重构为基于类的组件,因为我无法使用需要对类进行处理的钩子来做某些事情。但是我真的很喜欢这种钩子,我想坚持下去。向前迈进是好的吗?
很长的帖子,很抱歉,但是我认为这些有答案的问题对希望与本机反应挂钩的其他人很有用。
答案 0 :(得分:0)
您的错误是您将动作创建者与动作混淆了。顾名思义,动作创建者会在调用动作时创建一个动作。在您的情况下,您将分派一个动作创建者,而不是分派一个动作。您必须先调用该函数。
<TouchableOpacity
onPress={() => dispatch(countUp())}
>
// ...
<TouchableOpacity
onPress={() => dispatch(countDown())}
>
在上面的返工中,动作创建者在传递给调度之前被调用()
。
答案 1 :(得分:0)
您可以使用这个由React Hooks编写的小型库简化全局状态管理
yarn add @rawewhat/stora
然后像这样使用它
import useStora from '@rawewhat/stora'
const [states, actions] = useStora()
states.yourState
actions.yourAction()
答案 2 :(得分:0)
许多现有的React全局钩子库都在其中捆绑或修改了React。
此外,我不喜欢它们似乎都依赖于“字符串”作为键并且缺乏TypeScript强类型化的方式。
我只是想要一些简单的东西,没有任何可能会一直破坏或泄漏内存的不可思议的东西。
所以我写了我自己的。检查源代码-这非常简单:
https://www.npmjs.com/package/@fluffy-spoon/react-globalize
首先,您需要使用可选的初始值为状态全局创建密钥。
//users.ts
import { createGlobal } from '@fluffy-spoon/react-globalize';
export const usersKey = createGlobal([{ firstName: "John", lastName: "Doe" }]);
然后,您可以简单地在其中一个组件中使用它,就像使用useState
一样!
//index.ts
import { usersKey } from './users';
export const GlobalUserListComponent = () => {
//users and setUsers behaves like useState, except they are now shared between all components!
const [users, setUsers] = useGlobal(usersKey);
...
}