如何调用更新反应上下文状态/或调用非反应类的方法?
2019-11-02
2323
我有一个 React 上下文,它被用作跨多个组件的提供程序。
我想修改该状态并通过完全在 React 组件之外的常规方法更新 UI。即不是功能组件或类,只是一段普通的 JS 代码。
据我所知,提供程序/上下文只能从渲染方法或 React.FC 中访问
我可以传入一个函数
,但似乎只能从夹在
<Context.Provider>
之间的某种类型的 React 组件传入,并且
useContext
只有在相关项目传递到渲染循环后才会亮起。
有没有办法可以创建某种类型的
store
,我可以在其数据上调用
setState()
方法,但这种更新在 UI 中会是反应性的?
[edit] 我想要这个的原因是我有一个外部 API 调用我需要一个长时间运行的回调。我认为没有必要将该 API 包装在各种 React 内容中,因为我希望该模块可移植(例如移植到服务器端),并且只需与应用状态交互即可更新 UI 显示。
2个回答
据我所知,如果您想使用 React 构建 UI,您仍然需要选择加入 React API。
以下是您需要执行的操作:
- 需要一个上下文来在您的组件树中共享值
- 需要在根目录中有一个 Provider 组件
- 需要订阅外部 API 以接收新值并将其设置为您的上下文
- 使用上下文使用者获取共享值
以下是 示例 ,说明如何工作
Amin Paks
2019-11-03
我猜你问这个问题是因为你没有使用像 redux 这样的状态管理器,你可以从任何地方发送操作来重置状态。
正如你已经提到的,一个选项是创建你自己的商店和商店提供商。也许像这样的东西对你有用:
const store = (initialState => {
let value = initialState;
let listeners = [];
const getState = () => value;
const setState = fn => {
value = fn(value);
listeners.forEach(l => l(value));
};
const subscribe = listener => {
listeners.push(listener);
return () =>
(listeners = listeners.filter(f => f !== listener));
};
return { getState, setState, subscribe };
})({ counter: 1 }); //pass initial state to IIFE
const Store = React.createContext();
function Provider({ store, children }) {
const [state, setState] = React.useState(
store.getState()
);
React.useEffect(
() =>
store.subscribe(() => {
const lastState = store.getState();
//if a lot of setState calls are made synchronously
// do not update dom but let it batch update state
// before triggering a render
Promise.resolve().then(() => {
if (lastState === store.getState()) {
setState(store.getState());
}
});
}),
[store]
);
return (
<Store.Provider value={state}>
{children}
</Store.Provider>
);
}
function App() {
const state = React.useContext(Store);
return <div>{state.counter}</div>;
}
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
//call store setState from anywhere
setInterval(
() =>
store.setState(state => ({
...state,
counter: state.counter + 1,
})),
1000
);
<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>
HMR
2019-11-03