or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-conditions.mdbasic-conditions.mdindex.mdshorthand.mdswitch-case.md

async-conditions.mddocs/

0

# Asynchronous Conditions

1

2

Promise-based conditional rendering with loading states, error handling, and automatic promise cancellation. Enables clean handling of async operations within conditional rendering.

3

4

## Capabilities

5

6

### Async If Component

7

8

When the If component receives a Promise as its condition, it automatically handles the Promise lifecycle with loading, success, and error states.

9

10

```typescript { .api }

11

/**

12

* When condition is a Promise:

13

* - Renders Fallback block while Promise is pending

14

* - Renders Then block when Promise resolves

15

* - Renders Else block when Promise rejects

16

* - Supports promise cancellation via keepAlive prop

17

*/

18

const If: FC<{

19

condition: Promise<any>;

20

keepAlive?: boolean;

21

children: ReactNode;

22

}>;

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

import { If, Then, Else, Fallback } from "react-if";

29

30

// Basic async condition

31

<If condition={fetchUserData()}>

32

<Fallback>

33

<LoadingSpinner />

34

</Fallback>

35

<Then>

36

{(userData) => <UserProfile user={userData} />}

37

</Then>

38

<Else>

39

{(error) => <ErrorMessage error={error} />}

40

</Else>

41

</If>

42

43

// With keepAlive to prevent cancellation

44

<If condition={fetchCriticalData()} keepAlive={true}>

45

<Fallback>

46

<div className="loading">Loading critical data...</div>

47

</Fallback>

48

<Then>

49

{(data) => <CriticalDataView data={data} />}

50

</Then>

51

<Else>

52

{(error) => (

53

<div className="error">

54

Failed to load: {error.message}

55

<button onClick={retry}>Retry</button>

56

</div>

57

)}

58

</Else>

59

</If>

60

```

61

62

### Fallback Component

63

64

Loading state component that renders while a Promise condition is pending.

65

66

```typescript { .api }

67

/**

68

* Must contain only a single child, which it renders as-is.

69

* Should not be used outside of an <If /> block whose condition prop is a promise.

70

* Renders while the parent Promise condition is pending.

71

*/

72

const Fallback: FC<{

73

children?: ReactNode | (() => JSX.Element);

74

}>;

75

```

76

77

**Usage Examples:**

78

79

```typescript

80

// Simple loading indicator

81

<Fallback>

82

<div className="spinner">Loading...</div>

83

</Fallback>

84

85

// Function children for dynamic loading states

86

<Fallback>

87

{() => <AdvancedLoadingSpinner progress={loadingProgress} />}

88

</Fallback>

89

90

// Rich loading experience

91

<Fallback>

92

<div className="loading-container">

93

<LoadingSpinner />

94

<p>Fetching your data...</p>

95

<ProgressBar />

96

</div>

97

</Fallback>

98

```

99

100

### Promise Result Handling

101

102

Then and Else blocks receive the Promise result as their first parameter when used with async conditions.

103

104

```typescript { .api }

105

/**

106

* Function children for Then/Else blocks receive:

107

* @param returnValue - The resolved value (Then) or rejection error (Else)

108

* @param promiseHistory - Array of all promises passed to If

109

* @param cancellablePromise - The specific promise that triggered this render

110

*/

111

type AsyncChildrenFunction = (

112

returnValue: any,

113

promiseHistory: CancellablePromise[],

114

cancellablePromise: ExtendablePromise<any>

115

) => JSX.Element;

116

117

/**

118

* Enhanced Then component for async conditions - when used with Promise conditions,

119

* function children receive the resolved value as the first parameter

120

*/

121

interface AsyncThenProps {

122

children?: ReactNode | AsyncChildrenFunction;

123

}

124

125

/**

126

* Enhanced Else component for async conditions - when used with Promise conditions,

127

* function children receive the rejection error as the first parameter

128

*/

129

interface AsyncElseProps {

130

children?: ReactNode | AsyncChildrenFunction;

131

}

132

133

**Usage Examples:**

134

135

```typescript

136

// Access resolved data in Then block

137

<Then>

138

{(userData, history, promise) => (

139

<div>

140

<h1>Welcome, {userData.name}!</h1>

141

<p>Account created: {userData.createdAt}</p>

142

<small>Request ID: {promise.requestId}</small>

143

</div>

144

)}

145

</Then>

146

147

// Handle errors in Else block

148

<Else>

149

{(error, history, promise) => (

150

<div className="error">

151

<h3>Error loading data</h3>

152

<p>{error.message}</p>

153

<details>

154

<summary>Technical Details</summary>

155

<pre>{JSON.stringify({ error, promiseCount: history.length }, null, 2)}</pre>

156

</details>

157

<button onClick={() => retry(promise)}>Retry</button>

158

</div>

159

)}

160

</Else>

161

```

162

163

## Advanced Usage Patterns

164

165

### Promise Cancellation Control

166

167

```typescript

168

const DataComponent = ({ shouldKeepAlive, dataPromise }) => (

169

<If condition={dataPromise} keepAlive={shouldKeepAlive}>

170

<Fallback>

171

<div>

172

Loading data...

173

{!shouldKeepAlive && <small>Will cancel if component unmounts</small>}

174

</div>

175

</Fallback>

176

<Then>

177

{(data) => <DataDisplay data={data} />}

178

</Then>

179

<Else>

180

{(error) => <ErrorDisplay error={error} />}

181

</Else>

182

</If>

183

);

184

```

185

186

### Multiple Async Operations

187

188

```typescript

189

const MultiDataComponent = () => {

190

const [currentPromise, setCurrentPromise] = useState(null);

191

192

const loadUser = () => setCurrentPromise(fetchUser());

193

const loadPosts = () => setCurrentPromise(fetchPosts());

194

195

return (

196

<div>

197

<button onClick={loadUser}>Load User</button>

198

<button onClick={loadPosts}>Load Posts</button>

199

200

<If condition={currentPromise}>

201

<Fallback>

202

<LoadingIndicator />

203

</Fallback>

204

<Then>

205

{(data, history) => (

206

<div>

207

<DataDisplay data={data} />

208

<p>Total requests: {history.length}</p>

209

</div>

210

)}

211

</Then>

212

<Else>

213

{(error) => <ErrorMessage error={error} />}

214

</Else>

215

</If>

216

</div>

217

);

218

};

219

```

220

221

### Promise Chaining and History

222

223

```typescript

224

const ChainedDataLoader = ({ userId }) => {

225

const loadUserAndPosts = async () => {

226

const user = await fetchUser(userId);

227

const posts = await fetchUserPosts(user.id);

228

return { user, posts };

229

};

230

231

return (

232

<If condition={loadUserAndPosts()}>

233

<Fallback>

234

<div>Loading user and posts...</div>

235

</Fallback>

236

<Then>

237

{(data, history, currentPromise) => (

238

<div>

239

<UserProfile user={data.user} />

240

<PostsList posts={data.posts} />

241

<DebugInfo>

242

Promise history: {history.length} total requests

243

Current promise: {currentPromise.constructor.name}

244

</DebugInfo>

245

</div>

246

)}

247

</Then>

248

<Else>

249

{(error, history) => (

250

<div>

251

<ErrorDisplay error={error} />

252

<RetryButton

253

onRetry={() => window.location.reload()}

254

attempts={history.length}

255

/>

256

</div>

257

)}

258

</Else>

259

</If>

260

);

261

};

262

```

263

264

### Conditional Promise Execution

265

266

```typescript

267

const ConditionalDataLoader = ({ shouldLoad, params }) => {

268

// Only create promise when needed

269

const dataPromise = shouldLoad ? fetchData(params) : null;

270

271

return (

272

<div>

273

{dataPromise ? (

274

<If condition={dataPromise}>

275

<Fallback>Loading...</Fallback>

276

<Then>{(data) => <DataView data={data} />}</Then>

277

<Else>{(error) => <ErrorView error={error} />}</Else>

278

</If>

279

) : (

280

<div>Click load to fetch data</div>

281

)}

282

</div>

283

);

284

};

285

```

286

287

## Type Definitions

288

289

```typescript { .api }

290

interface ExtendablePromise<T> extends Promise<T> {

291

[index: string]: any;

292

}

293

294

interface CancellablePromise {

295

promise: ExtendablePromise<any>;

296

cancel: () => void;

297

}

298

299

interface AsyncSupportProps {

300

/**

301

* - False (default): promises are cancelled before each unmount

302

* - True: promises can be fulfilled even after a

303

* component unmount or a change to promise prop

304

*/

305

keepAlive?: boolean;

306

}

307

308

type ComponentWithConditionPropsAsyncSupport = {

309

condition: Promise<any>;

310

keepAlive?: boolean;

311

children: ReactNode;

312

};

313

314

type AsyncChildrenFunction = (

315

returnValue: any,

316

promiseHistory: CancellablePromise[],

317

cancellablePromise: ExtendablePromise<any>

318

) => JSX.Element;

319

```