React Context api - Consumer Does Not re-render after context changed
Your setJsonTran
just mutates the default value of the context which will not cause the value
given to the Provider
to change.
You could instead keep the jsonTransactions
in the topmost state and pass down a function that will change this state and in turn update the value
.
Example
const AppContext = React.createContext();
class App extends React.Component {
state = {
jsonTransactions: null
};
setJsonTran = data => {
this.setState({ jsonTransactions: data });
};
render() {
const context = this.state;
context.setJsonTran = this.setJsonTran;
return (
<AppContext.Provider value={context}>
<div className="App">
<header className="App-header">
<SubmitTransactionFile />
<WithdrawTransactionsTable />
</header>
</div>
</AppContext.Provider>
);
}
}
const AppContext = React.createContext();
class App extends React.Component {
state = {
jsonTransactions: null
};
setJsonTran = data => {
this.setState({ jsonTransactions: data });
};
render() {
const context = this.state;
context.setJsonTran = this.setJsonTran;
return (
<AppContext.Provider value={context}>
<div className="App">
<header className="App-header">
<SubmitTransactionFile />
<WithdrawTransactionsTable />
</header>
</div>
</AppContext.Provider>
);
}
}
class SubmitTransactionFile extends React.Component {
fileLoadedEvent(file, context) {
let files = file.target.files;
let reader = new FileReader();
if (files && files[0]) {
reader.readAsText(files[0]);
reader.onload = json => {
if (json && json.target) {
// slice just to not output too much in this example
context.setJsonTran(json.target.result.slice(0, 10));
}
};
}
}
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>
);
}
}
class WithdrawTransactionsTable extends React.Component {
render() {
return (
<AppContext.Consumer>
{context => (
<div>
<label>{context.jsonTransactions}</label>
</div>
)}
</AppContext.Consumer>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
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;