React Hooks 和 React-Redux 连接:让它们协同工作的最佳实践是什么?
React Hooks & React-Redux connect: What is the best practice to make them work together?
我想问一下社区,使用 react-redux connect()
和挂钩中的依赖管理结合现有代码的最佳实践是什么 useEffect()
.
让我们看下面的例子:
/* ... */
const mapStateToProps = (state) => ({
todos: getTodos(state),
currentUserId: getCurrentUserId(state)
})
const mapDispatchToProps = (dispatch) => ({dispatch})
const mapMergeProps = (stateProps, {dispatch}, ownProps) => {
return {
...stateProps,
...dispatchProps,
...ownProps,
fetchTodos: () => dispatch(fetchTodos(stateProps.currentUserId))
}
}
const TodosListContainer = connect(mapStateToProps, mapDispatchToProps, mapMergeProps)
const TodosList = ({todos, fetchTodos, ...props}) => {
const _fetchTodos = useCallback(fetchTodos, [])
useEffect(() => {
_fetchTodos()
}, [_fetchTodos])
return (
<ul>
{todos && todos.map((todo) => <li key={todo.id}>{todo.name}</li>)}
</ul>
)
}
上面代码中useEffect拥有所有的依赖,useCallback保证useEffect只被触发一次
然而,这似乎是一个额外的样板层:没有 useCallback,来自 connect 的 mapMergeToProps
作为 props 传递的函数将在每次状态更改时重新创建,并将触发 useEffect
.
我的问题是上面的代码是否正确,在描述的上下文中有更好的方法来处理 useEffect。
我会改成下面的样子
// Leave this one like it is
const mapStateToProps = (state) => ({
todos: getTodos(state),
currentUserId: getCurrentUserId(state)
})
// Map the fetchTodos here
const mapDispatchToProps = {
fetchTodos,
}
// Completely remove the mergeProps
const TodosListContainer = connect(mapStateToProps, mapDispatchToProps)
// Then use the hook like this
const TodosList = ({ todos, fetchTodos, currentUserId, ...props }) => {
useEffect(() => {
fetchTodos(currentUserId)
}, [fetchTodos, currentUserId])
return (
<ul>
{todos && todos.map((todo) => <li key={todo.id}>{todo.name}</li>)}
</ul>
)
}
这不会在每次渲染时触发 useEffect
,因为道具保持不变。它删除了(一些)样板代码。我还认为它更容易理解正在发生的事情,它会 运行 当 currentUserId
发生变化时产生影响,这可能是本应发生的事情。
我想问一下社区,使用 react-redux connect()
和挂钩中的依赖管理结合现有代码的最佳实践是什么 useEffect()
.
让我们看下面的例子:
/* ... */
const mapStateToProps = (state) => ({
todos: getTodos(state),
currentUserId: getCurrentUserId(state)
})
const mapDispatchToProps = (dispatch) => ({dispatch})
const mapMergeProps = (stateProps, {dispatch}, ownProps) => {
return {
...stateProps,
...dispatchProps,
...ownProps,
fetchTodos: () => dispatch(fetchTodos(stateProps.currentUserId))
}
}
const TodosListContainer = connect(mapStateToProps, mapDispatchToProps, mapMergeProps)
const TodosList = ({todos, fetchTodos, ...props}) => {
const _fetchTodos = useCallback(fetchTodos, [])
useEffect(() => {
_fetchTodos()
}, [_fetchTodos])
return (
<ul>
{todos && todos.map((todo) => <li key={todo.id}>{todo.name}</li>)}
</ul>
)
}
上面代码中useEffect拥有所有的依赖,useCallback保证useEffect只被触发一次
然而,这似乎是一个额外的样板层:没有 useCallback,来自 connect 的 mapMergeToProps
作为 props 传递的函数将在每次状态更改时重新创建,并将触发 useEffect
.
我的问题是上面的代码是否正确,在描述的上下文中有更好的方法来处理 useEffect。
我会改成下面的样子
// Leave this one like it is
const mapStateToProps = (state) => ({
todos: getTodos(state),
currentUserId: getCurrentUserId(state)
})
// Map the fetchTodos here
const mapDispatchToProps = {
fetchTodos,
}
// Completely remove the mergeProps
const TodosListContainer = connect(mapStateToProps, mapDispatchToProps)
// Then use the hook like this
const TodosList = ({ todos, fetchTodos, currentUserId, ...props }) => {
useEffect(() => {
fetchTodos(currentUserId)
}, [fetchTodos, currentUserId])
return (
<ul>
{todos && todos.map((todo) => <li key={todo.id}>{todo.name}</li>)}
</ul>
)
}
这不会在每次渲染时触发 useEffect
,因为道具保持不变。它删除了(一些)样板代码。我还认为它更容易理解正在发生的事情,它会 运行 当 currentUserId
发生变化时产生影响,这可能是本应发生的事情。