我希望能够从组件内部和外部更改值。
下面是我的尝试副本,来自 https://codesandbox.io/p/sandbox/42xrs2
问题已在沙箱中自我记录,这是一份副本:
App.js 文件:
import React, { useState } from "react";
import "./styles.css";
import TestParam from "./TestParam";
export default function App() {
const [outsideChange, setOutsideChange] = useState(null);
return (
<div className="App">
<button
onClick={() => {
setOutsideChange("");
setOutsideChange("Changed from outside");
}}
>
Change from the outside
</button>
<br />
<br />
<TestParam testStringProp={outsideChange} />
</div>
);
}
TestParam.js 文件:
import React, { useState, useEffect } from "react";
export default function TestParam({ testStringProp }) {
const [testString, setTestString] = useState(testStringProp);
useEffect(() => {
setTestString(testStringProp);
// alert("in useEffect");
}, [testStringProp]);
return (
<>
<button onClick={() => setTestString("changed from inside component")}>
Change from inside
</button>
<h1>Result here: {testString}</h1>
<p>Change from the ouside works if done before change from the inside</p>
<p>
Once changed from the inside, impossible to change again from the
outside
</p>
</>
);
}
外部状态实际上不会改变,因为 React 默认批量状态更新。当你打电话时
setOutsideChange("");
setOutsideChange("Changed from outside");
更新是组合的,也就是说状态没有被清除然后更新,并且看到当前和之前的状态是相同的,
testStringProp
的值实际上没有改变,并且useEffect
没有被触发。
一个简单的解决方案是更改您设置的值。例如,将
setOutsideChange("Changed from outside")
替换为 setOutsideChange(Math.random())
,您应该会看到它正在更新。
如果需要静态文本,则需要用
flushSync
包裹每个设置的状态,因此每个状态都会导致重新渲染,首先清除状态,然后设置文本。
const { useState, useEffect } = React;
const { flushSync, createRoot } = ReactDOM;
function App() {
const [outsideChange, setOutsideChange] = useState(null);
return (
<div className="App">
<button
onClick={() => {
flushSync(() => setOutsideChange(""));
flushSync(() => setOutsideChange("Changed from outside"));
}}
>
Change from the outside
</button>
<br />
<br />
<TestParam testStringProp={outsideChange} />
</div>
);
}
function TestParam({ testStringProp }) {
const [testString, setTestString] = useState(testStringProp);
useEffect(() => {
setTestString(testStringProp);
// alert("in useEffect");
}, [testStringProp]);
return (
<>
<button onClick={() => setTestString("changed from inside component")}>
Change from inside
</button>
<h1>Result here: {testString}</h1>
<p>Change from the ouside works if done before change from the inside</p>
<p>
Once changed from the inside, impossible to change again from the
outside
</p>
</>
);
}
createRoot(root).render(<App />);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>