将async componentDidMount()升级为async useEffect()



//UPDATE:问题是在useEffect()中设置状态后立即使用状态。

我试图升级我的一个React应用程序页面从类组件到功能组件与Hooks。然而,由于一些异步函数,我有一些问题。

旧页面的行为方式是,在componentDidMount()中,一些数据是从数据库异步获取并显示。工作正常,myNamemyValue显示正常

// OLD APPROACH - CLASS COMPONENT

class MyPage extends Component {
constructor(props) {
super(props);

this.state = {
myName: null,
myValue: undefined,
}
}

componentDidMount = async () => {

try {
const myName = await getNameFromDatabase();
const myValue = await getValueFromDatabase();


this.setState({ myName, myValue });

} catch (error) {
alert(
"Some errors occured when fetching from DB"
);
console.error(error);
}
}

render() {

return (
<div>
<h1>{this.state.myName}</h1>
<h1>{this.state.myValue}</h1>
</div>
)

}

export default MyPage

我试着按照这个回复来更新这个页面。

// NEW APPROACH - FUNCTIONAL COMPONENT WITH HOOKS
function MyPage() {

const [myName, setMyName] = useState(null);
const [myValue, setMyValue] = useState(undefined);

useEffect(() => {

async function fetchFromDatabase() {

const myName = await getNameFromDatabase();
const myValue = await getValueFromDatabase();

setMyName(myName);
setMyValue(myValue);

}

fetchFromDatabase();
}, [])

return (
<div>
<h1>{myName}</h1>
<h1>{myValue}</h1>
</div>
)

}

但是,当我这样做时,它们不再显示。我想它们仍然是"零"。和";undefined"。显然,如果我做一个console.log(),它们最终会被获取,但只有在没有它们的页面被渲染之后,这不是在第一种情况下发生的事情。

为什么会发生这种情况?为什么它在第一种情况下正确显示,但在第二种情况下却没有?据我所知,useEffect()componentDidMount()做同样的事情。如果我想在useEffect()内部调用异步函数,我应该继续另一种方式吗?

useEffect钩子和状态更新没有问题。函数组件是无实例的,所以this是未定义的。修复渲染,直接引用状态值。

处理异步代码时处理错误也是一个很好的做法。

function MyPage() {
const [myName, setMyName] = useState(null);
const [myValue, setMyValue] = useState(undefined);
useEffect(() => {
async function fetchFromDatabase() {
try {
const myName = await getNameFromDatabase();
const myValue = await getValueFromDatabase();
setMyName(myName);
setMyValue(myValue);
} catch(error) {
// handle any rejected Promises and thrown errors
}
}
fetchFromDatabase();
}, []);
return (
<div>
<h1>{myName}</h1>
<h1>{myValue}</h1>
</div>
);
}

首先,为响应指定与useState()相同的名称。试着用不同的名字。然后,将空字符串放入您的useState()默认值中,而不是null或undefined。最后,您不再需要使用this而是直接访问值。应该是这样的:

function MyPage() {
const [myName, setMyName] = useState('');
const [myValue, setMyValue] = useState('');
useEffect(() => {

async function fetchFromDatabase() {

const name = await getNameFromDatabase();
const value = await getValueFromDatabase();
setMyName(name);
setMyValue(value);
}
fetchFromDatabase();
}, [])
return (
<div>
<h1>{myName}</h1>
<h1>{myValue}</h1>
</div>
)
}
function MyPage() {
const [myName, setMyName] = useState(null);
const [myValue, setMyValue] = useState(undefined);
useEffect(() => {
(async () => {
const myName = await getNameFromDatabase();
const myValue = await getValueFromDatabase();
setMyName(myName);
setMyValue(myValue);
})();
}, []);
return (
<div>
<h1>{myName}</h1>
<h1>{myValue}</h1>
</div>
);
}

好的,所以原文中的代码是正确的正如其他人所说的那样。然而,它是我正在处理的实际代码的一个非常简化/抽象的版本。

我做错的是,我在设置后立即使用useEffect()的状态。

像这样:

// WRONG
let fetchedName= getNameFromDatabase();
setMyName(fetchedName);

if(myName==="something") {
setMyValue(1000);
}

结论是:永远不要在useEffect()componentWillMount()中设置后立即使用状态使用中间变量

而不是做的事:

// CORRECT
let fetchedName= getNameFromDatabase();
setMyName(fetchedName);

if(fetchedName==="something") {
setMyValue(1000);
}

最新更新