反应useState和setState行为错误

时间:2020-05-23 20:16:50

标签: javascript reactjs react-hooks

我一直在测试状态的变化,以便能够依赖于状态并计算其他状态,但是根据实现的不同,我会得到一些结果,尤其是有一个我不知道或不知道正在发生什么或为什么会得到该结果,请注意console.log()

情况:1

const [state, setState] = useState({count: 0});

const handleCount = () => {
    console.log(state); // prints {count: 0}
    setState(prevState => {
      prevState.count = prevState.count + 1;
      return prevState;
    });
    console.log(state); // prints {count: 1}
  }

useEffect(() => {
    console.log('has changed.. ' + state.count)
  }, [state]); // in this case this doesn't show any changes, so isn't renders anything, I need to render this value

// in render
<Button onClick={() => handleCount()}>
   Click {state.count}
</Button>

情况:2

const handleCount = () => {
    console.log(state); // prints {count: 0}
    setStateV(prevState => ({...prevState, count: prevState.count + 1}));
    console.log(state); // prints {count: 0}
  }

useEffect(() => {
    console.log('has changed.. ' + state.count)
  }, [state]); // it show that changed, but I cant depend on this because it haven't changed when I needed it

情况:3

const [state, setState] = useState(0);
const handleCount = () => {
  console.log(state); // prints 0
  setState(state => state + 1);
  console.log(state); // prints 0 it supposed to be 1!
}

我已经读过this,但根本没用

所以,我需要帮助以了解发生了什么...

5 个答案:

答案 0 :(得分:1)

在您的情况下,React使用Object.is比较状态对象{count: 0}。在第一种情况下,您只是更改属性计数并返回相同的对象。这就是为什么React认为状态没有改变的原因。请尝试下面的代码段

const myObj = { count: 0};
myObj.count = 3;

console.log(Object.is(myObj, myObj)); // returns true

但是,如果要在useState()内部使用对象,则在更新状态时,应始终使用Object.assign返回一个新对象,或者仅通过像这样破坏prevState对象即可。


const handleCount = () => {
    setState(prevState => {
         // if using Object.assign
         // return Object.assign(prevState, {count: prevState.count + 1})
         return {...prevState, count: prevState.count + 1}
    });
  }

或者对于简单的计数变量,您可以只使用

const [count, setCount] = useState(0);

const handleCount = () => {
  setCount(prevCount => (prevCount + 1))
}

答案 1 :(得分:0)

实际上,您是在修改prevState参数,这会导致错误的结果,请尝试以下操作:

setState(prevState => {
  const count = prevState.count + 1
  return { ...prevState, count }
})

答案 2 :(得分:0)

尝试一下:


const handleCount = () => {
    console.log(state);
    setState({...state, count: (state.count + 1)});
    console.log(state);
}

答案 3 :(得分:0)

功能setState没有回调功能选项(在类组件的this.setState中可用),因为它具有useEffect。试试看并检查控制台日志:

const handleCount = () => {
  console.log('initial state', state) // prints {count: 0}
  setState((prevState) => ({ ...prevState, count: prevState.count + 1 }))
  console.log(
    'state after Calling Async seState might not print latest state',
    state
  ) // prints {count: 0}
}


useEffect(() => {
  console.debug('state changed', state)
  // first print: { count: 0 } at mount
  // second print: { count: 1 }
}, [state])

答案 4 :(得分:0)

您已经在功能组件和类组件之间混合了状态。明确的概念是功能组件没有任何状态,但是具有useState挂钩。例如:

const [state, setState] = useState({count: 0});

尽管您将状态用于userState,但是这里状态只是一个变量。您可以像下面这样使用:

const [counter, setCounter] = useState({count: 0});

另一方面,对于类组件,您必须使用类似

的状态
constructor(props){
   super(props);
   this.state = {count: 0}
}

您可以在其中设置状态对象的地方

this.setState(prevState => {
    return {count: prevState.count+1}
});

请在下面的两个示例中使用功能组件和类组件

功能组件

import React, {useEffect, useState} from "react";

export default function Example() {

    const [state, setState] = useState({count: 0});

    const handleCount = () => {
        console.log(state); // prints {count: 0}
        setState({count: state.count+1});
        console.log(state); // prints {count: 1}
    };

    useEffect(() => {
        console.log('has changed.. ' + state.count)
    }, [state]);

    return (
        <div>
            <button onClick={() => handleCount()}>
                Click {state.count}
            </button>
        </div>
    );
}

类组件

import React from "react";

export default class Example extends React.Component{
    constructor(props){
        super(props);
        this.state = {count: 0}
    }

    handleCount = () => {
        console.log(this.state); // prints {count: 0}
        this.setState(prevState => {
            return {count: prevState.count+1}
        });
        console.log(this.state); // prints {count: 1}
    };

    render() {
        return (
            <div>
                <button onClick={() => this.handleCount()}>
                    Click {this.state.count}
                </button>
            </div>
        );
    }
}