回答を検索しましたが、回答が見つからなかったため、ここで質問します。コンテキストを更新するコンシューマーと、コンテキストを表示する必要のある別のコンシューマーがあります。 TypeScript(16.3)を使用しています
コンテキスト(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);
プロデューサー(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;
更新コンテキストコンシューマ(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;
そして最後にディスプレイコンシューマ(WithdrawTransactionsTable.tsx):
class WithdrawTransactionsTable extends React.Component {
render() {
return (
<AppContext.Consumer>
{ context =>
<div>
<label>{context.jsonTransactions}</label>
</div>
}
</AppContext.Consumer>
)
}
}
export default WithdrawTransactionsTable;
fileLoadedEvent
関数が呼び出された後、context.setJsonTran
は他のコンシューマーを再レンダリングし、WithdrawTransactionsTable
コンポーネントを再レンダリングする必要があることは私の理解ですが、実際にはレンダリングされません。
何がいけないの?
あなたのsetJsonTran
は、value
に与えられたProvider
を変更させないコンテキストのデフォルト値を変更するだけです。
代わりに、jsonTransactions
を最上位の状態に保ち、この状態を変更する関数を渡して、value
を更新することもできます。
例
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>