我有对象构造函数,该对象构造函数具有修改值的方法。 我在react组件中创建了该对象的新实例,并在子组件中呈现了该计数器。当我从child调用方法时,它在对象中得到了更新,但新的更新值未重新呈现。我试过用useEffect来监听道具的变化,但是在值更新时会调用它。但是当我更改子组件的状态时,将显示更新的值。有什么问题。
function Core() {
this.counter = 0;
}
Core.prototype.handleCounter = function(options) {
this.counter = this.counter + 1;
console.log(this.counter);
};
export default function App() {
let core = new Core();
return (
<div className="App">
<Status counter={core.counter} core={core} />
</div>
);
}
App.js
import React, { useEffect } from "react";
import "./styles.css";
export default function Status({ core, counter }) {
const [localState, setLocal] = React.useState(false);
function handleButton() {
core.handleCounter();
console.log(core.counter);
}
return (
<div>
<span> counter is {core.counter}</span>
<button onClick={() => handleButton()}>update object</button>
<button
onClick={() => {
setLocal(!localState);
}}
>
toggle localState
</button>
</div>
);
}
status.js
答案 0 :(得分:4)
React不知道addCurrency
的工作方式;它会看到一个变量Core
,它一旦创建就永远不会改变,因此React永远都不知道何时更新。
您似乎开始使用let core = new Core();
建立一个中央商店,因此您可能想查看useReducer
来处理不断增长的用例:
Core
答案 1 :(得分:0)
当状态改变,道具更改,useSelector返回的值与上次渲染的值不同,useContext返回的值与上次渲染或其他自定义的reducer值不同时,组件会更新。
值更改意味着不同的值,因此不同的原始值或不同的引用。这就是为什么您看到更新状态通常会复制旧状态:{...state,value:newValue}
而不是突变状态:state.value=newValue
。
App组件永远不会重新渲染,因为先前发生重新渲染的原因均未发生。这意味着它永远不会将更改的道具传递给状态。
您可以将本地状态用于计数器,上下文,状态管理器(例如redux或useReducer)。
这是在App中使用本地状态的简单示例
//not using React.memo because counter is the only thing
// that changes and causes re renders
function Status({ up, counter }) {
return (
<div>
<span> counter is {counter}</span>
<button onClick={() => up()}>up</button>
</div>
);
}
const App = () => {
const [counter, setCounter] = React.useState(0);
//not using useCallback because counter is the only thing
// that changes and causes re renders
const up = () => setCounter((c) => c + 1);
return <Status up={up} counter={counter} />;
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
如果要将逻辑保留在对象中,可以执行以下操作:
function createCore() {
let listeners = [];
//create a state container to mutate to to prevent
// stale closures for getState
const stateContainer = { state: { count: 0 } };
const trigger = (newState) =>
listeners.forEach((listener) => listener(newState));
const addListener = (fn) => {
listeners.push(fn);
return () =>
(listeners = listeners.filter(
(listener) => listener !== fn
));
};
const up = () => {
//mutate state container so getState does
// not pass a stale closure
const state = stateContainer.state;
stateContainer.state = {
...state,
count: state.count + 1,
};
trigger(stateContainer.state);
};
return {
addListener,
getState: () => stateContainer,
up,
};
}
const core = createCore();
function Status() {
//you could put this in a custom hook called
// useCore that returns core and state
const [state, setState] = React.useState(core.getState());
React.useEffect(
//addListener returns a function that will remove the
// listener when the component unmounts, this is
// automatically used as the cleanup function
() => core.addListener((state) => setState(state)),
[]
);
//custom hook would return [core,state]
return (
<div>
<span> counter is {state.count}</span>
<button onClick={core.up}>up</button>
</div>
);
}
const App = () => {
return <Status />;
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
答案 2 :(得分:0)
它对我来说是 100% 的工作
你可以像这样改变状态
[JsonIgnore]
或者如果你的 state 是 Array 你可以像这样改变
const [state, setState] = ({})
setState({...state})