React Context api - 上下文更改后消费者不会重新渲染
[英] React Context api - Consumer Does Not re-render after context changed
本文介绍了React Context api - 上下文更改后消费者不会重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我搜索了一个答案,但没有找到,所以我在这里问,我有一个更新上下文的消费者,和另一个应该显示上下文的消费者.我正在使用与打字稿(16.3)的反应
上下文(AppContext.tsx):
导出接口 AppContext {jsonTransactions: WithdrawTransactionsElement |空值;setJsonTran(jsonTransactions: WithdrawTransactionsElement | null): void;}导出 const appContextInitialState : AppContext = {jsonTransactions:空,setJsonTran : (数据:WithdrawTransactionsElement) =>{返回 appContextInitialState.jsonTransactions = 数据;}};export const AppContext = React.createContext(appContextInitialState);
生产者(App.tsx):
界面道具{}类 App 扩展了 React.Component{状态:AppContext = appContextInitialState;构造函数(道具:道具){超级(道具);}使成为() {返回 (<AppContext.Provider value={this.state}><div className="应用程序"><header className="App-header"><SubmitTransactionFile/><提款交易表/></标题>
</AppContext.Provider>);}}导出默认应用程序;
更新上下文消费者(SubmitTransactionFile.tsx)
class SubmitTransactionFile 扩展 React.Component {私有文件加载事件(文件:React.ChangeEvent,上下文:AppContext):无效{让文件 = file.target.files;let reader = new FileReader();如果(文件&& 文件[0]){reader.readAsText(文件[0]);reader.onload = (json) =>{如果(json && json.target){//@ts-ignore ->这是因为 typescript 编译器无法识别结果字段context.setJsonTran(JSON.parse(json.target.result))}}}}使成为() {返回 (<AppContext.Consumer>{上下文=><div className="SubmitTransactionFile"><label>选择交易文件</label><br/><input type="file" id="file" onChange={(file) =>this.fileLoadedEvent(file, context)}/><p>{context.jsonTransactions}</p>
}</AppContext.Consumer>)}}导出默认提交事务文件;
最后是显示消费者(WithdrawTransactionsTable.tsx):
class WithdrawTransactionsTable 扩展 React.Component {使成为() {返回 (<AppContext.Consumer>{上下文=><div><label>{context.jsonTransactions}</label>
}</AppContext.Consumer>)}}导出默认的 WithdrawTransactionsTable;
据我所知,在调用 fileLoadedEvent
函数后,context.setJsonTran
应该重新渲染其他消费者,并且 WithdrawTransactionsTable
组件应该是重新渲染,但没有.
我做错了什么?
解决方案
当你更新状态时,你不会触发提供者的重新渲染,因此消费者数据不会改变.您应该使用 setState 更新状态并将上下文值分配给提供者,如
class App extends React.Component{构造函数(道具:道具){超级(道具);this.state = {jsonTransactions:空,setJsonTran: this.setJsonTran};}setJsonTran : (数据:WithdrawTransactionsElement) =>{this.setState({jsonTransactions: 数据});}使成为() {返回 (<AppContext.Provider value={this.state}><div className="应用程序"><header className="App-header"><SubmitTransactionFile/><提款交易表/></标题>
</AppContext.Provider>);}}导出默认应用程序;
I searched for an answer but could not find any, so I am asking here,
I have a consumer that updates the context,
and another consumer that should display the context.
I am using react with typescript(16.3)
The Context(AppContext.tsx):
export interface AppContext {
jsonTransactions: WithdrawTransactionsElement | null;
setJsonTran(jsonTransactions: WithdrawTransactionsElement | null): void;
}
export const appContextInitialState : AppContext = {
jsonTransactions: null,
setJsonTran : (data: WithdrawTransactionsElement) => {
return appContextInitialState.jsonTransactions = data;
}
};
export const AppContext = React.createContext(appContextInitialState);
The Producer(App.tsx):
interface Props {}
class App extends React.Component<Props, AppContext> {
state: AppContext = appContextInitialState;
constructor(props : Props) {
super(props);
}
render() {
return (
<AppContext.Provider value={this.state}>
<div className="App">
<header className="App-header">
<SubmitTransactionFile/>
<WithdrawTransactionsTable />
</header>
</div>
</AppContext.Provider>
);
}
}
export default App;
The updating context consumer(SubmitTransactionFile.tsx)
class SubmitTransactionFile extends React.Component {
private fileLoadedEvent(file: React.ChangeEvent<HTMLInputElement>, context: AppContext): void{
let files = file.target.files;
let reader = new FileReader();
if (files && files[0]) {
reader.readAsText(files[0]);
reader.onload = (json) => {
if (json && json.target) {
// @ts-ignore -> this is because result field is not recognized by typescript compiler
context.setJsonTran(JSON.parse(json.target.result))
}
}
}
}
render() {
return (
<AppContext.Consumer>
{ context =>
<div className="SubmitTransactionFile">
<label>Select Transaction File</label><br />
<input type="file" id="file" onChange={(file) =>
this.fileLoadedEvent(file, context)} />
<p>{context.jsonTransactions}</p>
</div>
}
</AppContext.Consumer>
)
}
}
export default SubmitTransactionFile;
and finaly the display consumer(WithdrawTransactionsTable.tsx):
class WithdrawTransactionsTable extends React.Component {
render() {
return (
<AppContext.Consumer>
{ context =>
<div>
<label>{context.jsonTransactions}</label>
</div>
}
</AppContext.Consumer>
)
}
}
export default WithdrawTransactionsTable;
It is my understanding that after fileLoadedEvent
function is called the context.setJsonTran
should re-render the other consumers and WithdrawTransactionsTable
component should be re-rendered , but it does not.
what am I doing wrong?
解决方案
When you update the state, you aren't triggering a re-render of the Provider and hence the consumer data doesn't change. You should update the state using setState and assign context value to provider like
class App extends React.Component<Props, AppContext> {
constructor(props : Props) {
super(props);
this.state = {
jsonTransactions: null,
setJsonTran: this.setJsonTran
};
}
setJsonTran : (data: WithdrawTransactionsElement) => {
this.setState({
jsonTransactions: data
});
}
render() {
return (
<AppContext.Provider value={this.state}>
<div className="App">
<header className="App-header">
<SubmitTransactionFile/>
<WithdrawTransactionsTable />
</header>
</div>
</AppContext.Provider>
);
}
}
export default App;
这篇关于React Context api - 上下文更改后消费者不会重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!