如何确保应用等待Reducer获取异步请求数据后再读取该数据?
Hey, I totally get why this is happening—you're running into a classic async timing issue here. Let me break it down first:
When you call this.props.actions.getInterfaceFile(event.data.fileId), that fires off an HTTP request which takes time to complete. But right after that, you immediately try to log this.props.interfaceFile.fileBlob and update state with it. At that moment, the request hasn't finished yet, so your reducer hasn't updated the interfaceFile state—it's still undefined, hence the TypeError. On the second click, the data's already in your state from the first successful request, so it works.
Here are a few solid solutions to fix this, ordered by recommendation:
1. Wait for the async action to resolve (Best Approach)
If your getInterfaceFile action uses Axios (which returns a Promise), you can chain a .then() to wait for the request to finish before accessing the data. First, make sure your action creator returns the Promise from Axios:
// Example action creator export const getInterfaceFile = (fileId) => { return dispatch => { // Return the Axios Promise so we can chain .then() return axios.get(`/your-api-endpoint/${fileId}`, { responseType: 'blob' }) .then(response => { dispatch({ type: LOAD_INTERFACE_FILE_LOADING_SUCCESS, interfaceFile: response.data }); }); }; };
Then update your onCellClicked handler to wait for the promise to resolve:
onCellClicked(event) { if (event.column.colId === 'fileId') { this.props.actions.getInterfaceFile(event.data.fileId) .then(() => { // Now interfaceFile is updated in state/props! console.log(this.props.interfaceFile.fileBlob); // Convert blob to base64 (you'll need this for decodedFile) const reader = new FileReader(); reader.onload = () => { this.setState({ showModal: true, fileDataBase64: reader.result }); }; reader.readAsDataURL(this.props.interfaceFile.fileBlob); }) .catch(error => { // Don't forget to handle errors! console.error('Failed to fetch file:', error); }); } }
2. Use Component Lifecycle to Watch for Prop Changes
Since you're using a class component, you can leverage componentDidUpdate to detect when interfaceFile gets updated in props, then run your logic:
// Add this lifecycle method to your component componentDidUpdate(prevProps) { // Only run if interfaceFile just became available if (!prevProps.interfaceFile && this.props.interfaceFile) { console.log(this.props.interfaceFile.fileBlob); // Convert blob to base64 const reader = new FileReader(); reader.onload = () => { this.setState({ fileDataBase64: reader.result }); }; reader.readAsDataURL(this.props.interfaceFile.fileBlob); } } // Update your click handler to just trigger the request and open the modal onCellClicked(event) { if (event.column.colId === 'fileId') { this.props.actions.getInterfaceFile(event.data.fileId); this.setState({ showModal: true }); } }
This is great if you don't want to modify your existing action creators—it lets the lifecycle handle the timing for you.
3. Quick Fix: Guard Clauses (Temporary)
If you need a quick band-aid to avoid the error (though this isn't the cleanest solution), you can add a check to make sure interfaceFile exists before accessing it. You could even add a small interval to wait for the data, but I don't recommend this long-term:
onCellClicked(event) { if (event.column.colId === 'fileId') { this.props.actions.getInterfaceFile(event.data.fileId); this.setState({ showModal: true }); // Poll until the data is available (not ideal, but works for testing) const checkInterval = setInterval(() => { if (this.props.interfaceFile?.fileBlob) { console.log(this.props.interfaceFile.fileBlob); // Convert to base64 here const reader = new FileReader(); reader.onload = () => { this.setState({ fileDataBase64: reader.result }); clearInterval(checkInterval); }; reader.readAsDataURL(this.props.interfaceFile.fileBlob); } }, 100); } }
One More Thing: Handling the Blob to Base64
You mentioned decodedFile—I added a FileReader example in each solution because you'll need to convert the fileBlob to a base64 string to use it in your state. That's the standard way to handle Blob data for display in modals or image previews.
内容的提问来源于stack exchange,提问作者Arya

