React Context api - 上下文更改后消费者不会重新渲染 [英] React Context api - Consumer Does Not re-render after context changed

查看:117
本文介绍了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屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆