为什么 useState 钩子调用初始化值代码两次?



假设我们有以下代码:

const [obj, setobj] = useState(generateInitialObj());

为什么 generateInitialObj(( 被调用两次?我已经添加了日志记录来生成InitialObj((,我刚刚注意到它。它似乎发生在组件生命周期的最初阶段。不过,一旦反应从那里获得价值,它就会永远留在那里。无需重新获取它。 有什么想法吗?

这是一个JavaScript技术问题。React 无法阻止在每次渲染时调用generateInitialObj。考虑到这一点,React 支持以下 API:

const [obj, setobj] = useState(() => generateInitialObj());

刚刚测试并确认,如果您使用函数调用getInitialState(),则每次都会调用它,因为它确实是正常的JS行为。

function getInitialState() {
console.log('Executing getInitialState...');
return({
propA: 'foo',
propB: 'bar'
});
}
function App() {
console.log('Rendering App...');
const [myState,setMyState] = React.useState(getInitialState());
const [myBoolean,setMyBoolean] = React.useState(false);

function updateApp() {
setMyBoolean((prevState) => !prevState);
}

function changeAppState() {
setMyState({
propA: 'foo2',
propB: 'bar2'
});
}

return(
<React.Fragment>
<div>myState.propA: {myState.propA}</div>
<div>myState.propB: {myState.propB}</div>
<button onClick={updateApp}>Update App</button>
<button onClick={changeAppState}>Change App State</button>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

但是,如果您改用函数声明()=>getInitialState(),则只会调用一次。

function getInitialState() {
console.log('Executing getInitialState...');
return({
propA: 'foo',
propB: 'bar'
});
}
function App() {
console.log('Rendering App...');
const [myState,setMyState] = React.useState(()=>getInitialState());
const [myBoolean,setMyBoolean] = React.useState(false);

function updateApp() {
setMyBoolean((prevState) => !prevState);
}

function changeAppState() {
setMyState({
propA: 'foo2',
propB: 'bar2'
});
}

return(
<React.Fragment>
<div>myState.propA: {myState.propA}</div>
<div>myState.propB: {myState.propB}</div>
<button onClick={updateApp}>Update App</button>
<button onClick={changeAppState}>Change App State</button>
</React.Fragment>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

除此之外,两者的工作方式都是一样的。

我认为组件re-rendering是这背后的原因。 你能发布组件层次结构吗?

也试试这个:

const [obj, setobj] = useState(() => generateInitialObj());

这是一个工作示例: https://stackblitz.com/edit/react-mysrjp

相关内容

最新更新