Created
April 29, 2021 18:12
-
-
Save bazen-teklehaymanot/38e29b3dd4b9d08a02c2f0cbf7b0aedd to your computer and use it in GitHub Desktop.
Conditional rendering in react
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ReactDOM from 'react-dom'; | |
import React, { Fragment, FC, useState, useEffect } from 'react'; | |
import reportWebVitals from './reportWebVitals'; | |
export enum StateTypes{ | |
Init='INIT', | |
Error='ERROR', | |
Success='SUCCESS', | |
Processing='PROCESSING', | |
} | |
export function useAsync<TPayload>(asyncTask:Function):StateMachine<TPayload> { | |
const [ state, setState ] = useState<StateMachine<TPayload>>({ currentState:StateTypes.Init}); | |
useEffect(()=>{ runAsyncTasks(); },[]); | |
async function runAsyncTasks(){ | |
try{ | |
setState({ currentState:StateTypes.Processing,message:'Loading...'}) | |
const result = await asyncTask(); | |
setState({ currentState:StateTypes.Success,message:'Success',payload:result}) | |
}catch(error){ | |
setState({currentState:StateTypes.Error,error, message: error.message}) | |
} | |
} | |
return state; | |
} | |
export interface StateMachine<T>{ | |
currentState: StateTypes | |
payload?: T | |
error?:Error | |
message?: string | |
} | |
interface StateMachineWrapperProps{ | |
asyncTask: Function | |
component: React.ComponentType<any> | |
} | |
interface ConditionalRendererProps{ | |
activeState: string | |
mapping: { [key: string]:React.ReactNode} | |
} | |
export const ConditionalRenderer:FC<ConditionalRendererProps>=(props)=>{ | |
return( | |
<Fragment> | |
{ props.mapping[props.activeState] } | |
</Fragment> | |
) | |
} | |
export const StateMachineWrapper:FC<StateMachineWrapperProps> =(props) =>{ | |
const machine = useAsync<string>(props.asyncTask) | |
return ( | |
<ConditionalRenderer | |
activeState={machine.currentState} | |
mapping={{ | |
[StateTypes.Init]:<Fragment/>, | |
[StateTypes.Processing]: <p>{machine.message}</p>, | |
[StateTypes.Error]: <p>{machine.message}</p>, | |
[StateTypes.Success]: <props.component {...machine.payload}/> | |
}} | |
/> | |
) | |
} | |
function longRunningTask(){ | |
return new Promise((resolve, reject)=>{ | |
setTimeout(()=>{ | |
resolve({data: 'Async task completed'}) | |
},1000) | |
}); | |
} | |
interface ContentProps{ | |
data: string | |
} | |
export const Content:FC<ContentProps>=(props)=>{ | |
return ( | |
<div> | |
<h3>Content</h3> | |
<p>{ props.data }</p> | |
</div> | |
) | |
} | |
export const ContentWrapper:FC =()=>{ | |
return ( | |
<StateMachineWrapper | |
asyncTask={longRunningTask} | |
component={Content}/> | |
) | |
} | |
ReactDOM.render( | |
<React.StrictMode> | |
<ContentWrapper /> | |
</React.StrictMode>, | |
document.getElementById('root') | |
); | |
reportWebVitals(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment