不明白如何更新 React 钩子



我已经试着问了几十次这个难以回答的问题。我已经做了一个最简单的例子来问这个问题。

我在handleChange方法中更改了钩子的值。但console.log总是显示以前的值,而不是新的值。为什么?

我需要更改钩子的值,然后用它来做其他事情,而不是做console.log。但我做不到,因为钩子总是没有我刚想放进去的东西。

const options = ["Option 1", "Option 2"];
export default function ControllableStates() {
const [value, setValue] = React.useState(options[0]);
const handleChange = val => {
setValue(val);
console.log(value);
};
return (
<div>
<div>{value}</div>
<br />
<Autocomplete
value={value}
onChange={(event, newValue) => {
handleChange(newValue);
}}
options={options}
renderInput={params => (
<TextField {...params} label="Controllable" variant="outlined" />
)}
/>
</div>
);
}

你可以在这里试试。https://codesandbox.io/s/awesome-lumiere-y2dww?file=/src/App.js

我认为问题在于您将值记录在handleChange函数中。控制台记录函数之外的值会记录正确的值。链接:https://codesandbox.io/s/async-fast-6y71b

钩子不会立即更新您想要更新的值,正如您对类所期望的那样(尽管这也不能保证)

状态挂钩,当调用setValue时将触发重新渲染。在该新渲染中,状态将具有预期的新值。这就是为什么console.log看到旧值的原因。

可以想象,在每次渲染中,状态值只是该组件函数调用的局部变量。并将渲染的结果视为该渲染调用中状态+道具的结果。无论这两个选项中的任何一个发生变化(父组件中的道具;setXXX函数中的状态),都会触发新的渲染。

如果将console.log移出回调处理程序的外部(即,在渲染的主体中),您将在交互后发生的渲染中看到状态被正确记录。

从这个意义上说,在交互的回调事件中,你只需要担心正确更新状态,下一次渲染会注意,在新的道具/状态下,重新渲染结果

该值不会同步"更改"-它甚至是用const声明的,因此即使它在同一范围内更改的概念也没有意义。

当使用钩子更改状态时,当重新绘制组件时,会看到新值。因此,要使用"新值"进行日志记录和操作,请在函数的主体中进行检查:

const ControllableStates = () => {
const [value, setValue] = React.useState(options[0]);
const handleChange = val => {
setValue(val);
};
// ADD LOG HERE:
console.log('New or updated value:', value);
return (
<div>
<div>{value}</div>
<br />
<Autocomplete
value={value}
onChange={(event, newValue) => {
handleChange(newValue);
}}
options={options}
renderInput={params => (
<TextField {...params} label="Controllable" variant="outlined" />
)}
/>
</div>
);
}

您打印的是handleChange中的旧value,而不是新val。即

const handleChange = val => {
setValue(val);
console.log(value);
};

应为:

const handleChange = val => {
setValue(val);
console.log(val);
};

实际上,让我们回顾一下这个场景背后的逻辑。您应该只使用"handleChange"函数来更新状态挂钩,并让其他事情来执行。逻辑取决于该状态挂钩值,这主要是使用"useEffect"挂钩完成的。

你可以重构你的代码如下:

const handleChange = val => {
setValue(val);
};
React.useEffect(() => {
console.log(value);
// do your logic here
}, [value])

所以我认为主要的问题是你不了解React处理组件和状态。

因此,我将大大简化React的工作。

  • React渲染一个新组件并记住它的状态和输入(aka道具),这是孩子们的状态和投入
  • 如果在任何给定点输入或状态发生变化,React将呈现通过调用组件函数再次调用组件

考虑一下:

function SomeComponent(text) {
return (<div>The <i>text</i> prop has the value {text}</div>)
}

假设初始prop值为"abc",React将调用SomeComponent("abc"),然后函数返回CCD_ 14和React将对此进行渲染。如果道具text没有改变,那么React就什么都不做了。

现在父组件将prop更改为"def",现在React将调用SomeComponent("def"),它将返回<div>The <i>text</i> prop has the value def</div>,这与最后一次调用,因此React将更新DOM以反映更改。

现在让我们介绍一下状态

function SomeComponent() {
const [name, setName] = React.useState("John")
function doSomething()
{
alert("The name is " + name)
}
return (
<p>Current name: {name}</p>
<button onClick={() => setName("Mary")}>Set name to Mary</button>
<button onClick={() => setName("James")}>Set name to James</button>
<button onClick={() => doSomething()}>Show current name</button>
)
}

因此这里React将调用SomeComponent()并呈现名称John和3按钮请注意,name变量的值在当前执行,因为它被声明为const。此变量仅反映状态的最新值。

当您按下第一个按钮时,将执行setName()。React将在内部存储状态的新值,并且由于状态的更改,它将呈现则SomeComponent()将被再次调用。现在变量name将再次反映状态的最新值(useState就是这样做的),因此在本例中Mary。反应将意识到DOM必须更新,并打印名称Mary

如果按下第三个按钮,它将调用doSomething(),CCD_26将打印name变量的最新值,因为每次React调用SomeComponent(),使用最新的CCD_ 30的值。所以,一旦你打电话给setName(),你就不需要任何特别的东西都可以获得新的价值。React将负责调用组件功能。

因此,当你不使用类组件而是使用函数组件时,你必须思考不同的是:React一直在调用函数执行它反映特定时间点的最新状态。所以当你调用useState钩子的setter,您知道组件函数将并且CCD_ 33将返回新的值。

我建议您阅读这篇文章,也请再次阅读组件和React文档中的道具。

那么你应该如何进行呢?像这样:

const options = ["Option 1", "Option 2"];
export default function ControllableStates() {
const [value, setValue] = React.useState(options[0]);
const handleChange = val => {
setValue(val);
console.log(value);
};
const handleClick = () => {
// DOING SOMETHING WITH value
alter(`Now I'm going to do send ${value}`);
}
return (
<div>
<div>{value}</div>
<br />
<Autocomplete
value={value}
onChange={(event, newValue) => {
handleChange(newValue);
}}
options={options}
renderInput={params => (
<TextField {...params} label="Controllable" variant="outlined" />
)}
/>
<button type="button" onClick={handleClick}>Send selected option</button>
</div>
);
}

请参阅CodeSandbox。

相关内容

  • 没有找到相关文章

最新更新