依赖项值更改时,useEffect不起作用

时间:2020-02-03 08:50:15

标签: javascript reactjs react-native react-redux

我从React钩子那里经历过useEffect函数。当我将它与React-redux的useSelector一起使用时,它是如此奇怪。

我的减速器:

const initialState = { a: 0 };

function mainReducer(state = initialState, action) {
  const { type, payload } = action;
  switch (type) {
    case 'A': return { ...state, a: payload }
    default:
      return state;
  }
}

我的组件

function MyComponent(props) {
  const { a } = useSelector(state => state.mainReducer);
  const dispatch = useDispatch(); 
  
  useEffect(() => {
    console.log('did mount: ', a);
    dispatch({ type: 'A', payload: 1 })
  }, []); 

  useEffect(() => {
    console.log('use effect: ', a);
    dispatch({ type: 'A', payload: a });
  }, [a]) 

  return (<View style={styles.container}>
    <Text style={styles.text}>{a}</Text>
  </View>);
};

结果

日志:

did mount ran: 0
useEffect ran: 0

最后一个结果是变量'a'= 0

????

据我了解, 第一次渲染后,两种效果均按其顺序在代码中依次运行。
(第1步)首先运行效果->登录'did mount ran:0'。然后将值1分配到存储
(第2步)第二个效果在-> log'did mount ran:0'之后运行。然后将值0分配给存储

但是我不明白的是,第二个效果必须跟踪变量'a'的变化,因此会有:
在以下渲染时间内:
(第3步)当值“ a”从0变为1(从第1步开始)时,应运行第二个useEffect。
然后:
(第4步),当值再次从1更改为0(第2步)时,应该进行第三次重新渲染。

因此日志应为:

did mount ran: 0
useEffect ran: 0
useEffect ran: 1
useEffect ran: 0

能否请您向我解释我所缺少的内容?谢谢

2 个答案:

答案 0 :(得分:4)

您的两个调度都在第一次渲染之后被调用,因此即使您的第二个渲染值是0之前,您的第二个useEffect也将无法检测到变化,因为没有变化。

让我们看看您的渲染方法中发生了什么

首次渲染:

a = 0

首次使用效果:dispatch({a:1})

第二次useEffect:dispatch({a:0})

现在在您的redux存储中,a为0。

第二次渲染

a = 0

第一次useEffect:由于没有依赖项而无法运行

第二次useEffect:不会随着汉斯的更改而运行。

答案 1 :(得分:1)

请停止使用

 useSelector(state => state.mainReducer);

没有任何意义

应该有一个简单的状态转换(子选择)

const a = useSelector(state => state.a)

直接来自redux文档:

const counter = useSelector(state => state.counter)  

更新

您可以看到成分稍有变化的效果(来自商店更改)

function MyComponent(props) {
  const a = useSelector(state => state.a);
  const dispatch = useDispatch(); 

  console.log('render: ', a);

  useEffect(() => {
    console.log('use effect: ', a);
    dispatch({ type: 'A', payload: a });
  }, [a]) 

  useEffect(() => {
    console.log('did mount: ', a);
    dispatch({ type: 'A', payload: 1 })
  }, []); 

  return (<View style={styles.container}>
    <Text style={styles.text}>{a}</Text>
  </View>);
};

它应该导致日志:

  • render: 0 //初始状态
  • use effect: 0 //首次运行
  • //调度0 ...由reducer在存储中处理,但结果相同。
    // ...,并且在渲染过程中,我们仍在处理从渲染开始时的状态读取的“旧” a
  • did mount: 0 //'旧'a
    //派发1 ...在redux存储中更改状态
  • ....呈现的文本0
    ...
    ...

  • // useSelector强制重新呈现-检测到更改

  • render: 1 //最新的调度值,由减速器处理为新状态,由选择器重新读取
  • use effect: 1 // useEffect 由于a的变化而按预期工作
  • ....呈现文本1

...
...

  • 不再重新提交-最新分发状态未更改

当然,从其他组件进行分派将强制在此组件中进行更新...如果值将不同。