or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-utilities.mddevelopment-styling.mddom-utilities.mdindex.mdreact-components.mdreact-hooks.md

react-hooks.mddocs/

0

# React Hooks

1

2

Modern React hooks for state management, memoization, and lifecycle optimization with enhanced functionality beyond standard React hooks.

3

4

## Capabilities

5

6

### useMergedState (useControlledState)

7

8

Hook for managing controlled/uncontrolled state patterns, commonly used in form components that can be either controlled or uncontrolled.

9

10

```typescript { .api }

11

/**

12

* Hook for controlled/uncontrolled state management

13

* @param {T | (() => T)} defaultStateValue - Default state value or function

14

* @param {object} [option] - Configuration options

15

* @returns {[R, (value: T) => void]} State value and setter function

16

*/

17

function useControlledState<T, R = T>(

18

defaultStateValue: T | (() => T),

19

option?: {

20

/** Default value when component is uncontrolled */

21

defaultValue?: T | (() => T);

22

/** External value when component is controlled */

23

value?: T;

24

/** Callback when value changes */

25

onChange?: (value: T, prevValue: T) => void;

26

/** Transform state value before returning */

27

postState?: (value: T) => T;

28

}

29

): [R, (value: T) => void];

30

```

31

32

**Usage Examples:**

33

34

```typescript

35

import useControlledState from 'rc-util/lib/hooks/useMergedState';

36

37

// Basic controlled/uncontrolled input

38

function Input({ value, defaultValue, onChange }) {

39

const [inputValue, setInputValue] = useControlledState('', {

40

value,

41

defaultValue,

42

onChange

43

});

44

45

return (

46

<input

47

value={inputValue}

48

onChange={(e) => setInputValue(e.target.value)}

49

/>

50

);

51

}

52

53

// With post-processing

54

function NumberInput({ value, onChange }) {

55

const [numValue, setNumValue] = useControlledState(0, {

56

value,

57

onChange,

58

postState: (val) => Math.max(0, val) // Ensure non-negative

59

});

60

61

return (

62

<input

63

type="number"

64

value={numValue}

65

onChange={(e) => setNumValue(Number(e.target.value))}

66

/>

67

);

68

}

69

70

// Uncontrolled with default

71

<Input defaultValue="Hello" />

72

73

// Controlled

74

<Input value={inputValue} onChange={setInputValue} />

75

```

76

77

### useEffect

78

79

Enhanced useEffect that passes previous dependencies to the callback, useful for comparison logic.

80

81

```typescript { .api }

82

/**

83

* Enhanced useEffect that passes previous dependencies to callback

84

* @param {(prevDeps: any[]) => void} callback - Effect callback receiving previous deps

85

* @param {any[]} deps - Dependencies array

86

*/

87

function useEffect(

88

callback: (prevDeps: any[]) => void,

89

deps: any[]

90

): void;

91

```

92

93

**Usage Example:**

94

95

```typescript

96

import useEffect from 'rc-util/lib/hooks/useEffect';

97

98

function Component({ userId, filterType }) {

99

useEffect((prevDeps) => {

100

const [prevUserId, prevFilterType] = prevDeps;

101

102

// Only refetch if userId changed, not filterType

103

if (prevUserId !== userId) {

104

fetchUserData(userId);

105

}

106

107

// Only update filter if filterType changed

108

if (prevFilterType !== filterType) {

109

updateFilter(filterType);

110

}

111

}, [userId, filterType]);

112

}

113

```

114

115

### useMemo

116

117

Custom memoization hook with custom comparison function for more control over when values are recalculated.

118

119

```typescript { .api }

120

/**

121

* Custom memoization hook with custom comparison function

122

* @param {() => Value} getValue - Function to get the memoized value

123

* @param {Condition} condition - Current condition for comparison

124

* @param {(prev: Condition, next: Condition) => boolean} shouldUpdate - Comparison function

125

* @returns {Value} Memoized value

126

*/

127

function useMemo<Value, Condition = any[]>(

128

getValue: () => Value,

129

condition: Condition,

130

shouldUpdate: (prev: Condition, next: Condition) => boolean

131

): Value;

132

```

133

134

**Usage Examples:**

135

136

```typescript

137

import useMemo from 'rc-util/lib/hooks/useMemo';

138

139

// Deep comparison for objects

140

function ExpensiveComponent({ config }) {

141

const processedData = useMemo(

142

() => expensiveCalculation(config),

143

config,

144

(prev, next) => JSON.stringify(prev) !== JSON.stringify(next)

145

);

146

147

return <div>{processedData}</div>;

148

}

149

150

// Custom comparison for arrays

151

function ListComponent({ items, sortBy }) {

152

const sortedItems = useMemo(

153

() => [...items].sort((a, b) => a[sortBy] - b[sortBy]),

154

{ items, sortBy },

155

(prev, next) =>

156

prev.items.length !== next.items.length ||

157

prev.sortBy !== next.sortBy ||

158

prev.items.some((item, index) => item.id !== next.items[index]?.id)

159

);

160

161

return (

162

<ul>

163

{sortedItems.map(item => <li key={item.id}>{item.name}</li>)}

164

</ul>

165

);

166

}

167

```

168

169

## Reference Utilities

170

171

### ref

172

173

React ref manipulation utilities for working with refs in complex scenarios.

174

175

```typescript { .api }

176

/**

177

* Fill a ref with a node value

178

* @param {React.Ref<T>} ref - Ref to fill (function or object ref)

179

* @param {T} node - Node value to assign

180

*/

181

function fillRef<T>(ref: React.Ref<T>, node: T): void;

182

183

/**

184

* Merge multiple refs into one ref function

185

* @param {...React.Ref<T>[]} refs - Refs to merge

186

* @returns {React.Ref<T>} Combined ref function

187

*/

188

function composeRef<T>(...refs: React.Ref<T>[]): React.Ref<T>;

189

190

/**

191

* Check if a component supports refs

192

* @param {any} nodeOrComponent - React component or node

193

* @returns {boolean} True if component supports refs

194

*/

195

function supportRef(nodeOrComponent: any): boolean;

196

```

197

198

**Usage Examples:**

199

200

```typescript

201

import { fillRef, composeRef, supportRef } from 'rc-util/lib/ref';

202

203

// Compose multiple refs

204

function ForwardedComponent(props, ref) {

205

const internalRef = useRef();

206

const combinedRef = composeRef(ref, internalRef);

207

208

useEffect(() => {

209

// Use internal ref for component logic

210

if (internalRef.current) {

211

internalRef.current.focus();

212

}

213

}, []);

214

215

return <input ref={combinedRef} />;

216

}

217

218

// Check ref support before using

219

function ParentComponent({ children }) {

220

const childRef = useRef();

221

222

const enhancedChildren = React.Children.map(children, (child) => {

223

if (supportRef(child)) {

224

return React.cloneElement(child, { ref: childRef });

225

}

226

return child;

227

});

228

229

return <div>{enhancedChildren}</div>;

230

}

231

232

// Manual ref filling

233

function CustomRef() {

234

const handleRef = useCallback((node) => {

235

// Fill multiple refs manually

236

fillRef(externalRef, node);

237

fillRef(internalRef, node);

238

}, []);

239

240

return <div ref={handleRef} />;

241

}

242

```

243

244

## Animation & Performance

245

246

### raf

247

248

RequestAnimationFrame wrapper with fallback for server-side rendering and older browsers.

249

250

```typescript { .api }

251

/**

252

* RequestAnimationFrame wrapper with fallback

253

* @param {() => void} callback - Function to call on next frame

254

* @returns {number} Request ID for cancellation

255

*/

256

function wrapperRaf(callback: () => void): number;

257

258

/**

259

* Cancel a requestAnimationFrame request

260

* @param {number} id - Request ID to cancel

261

*/

262

wrapperRaf.cancel: (id: number) => void;

263

```

264

265

**Usage Example:**

266

267

```typescript

268

import raf from 'rc-util/lib/raf';

269

270

// Schedule animation

271

const rafId = raf(() => {

272

// Animation code here

273

element.style.opacity = '1';

274

});

275

276

// Cancel if needed

277

raf.cancel(rafId);

278

279

// Use in custom hook

280

function useAnimationFrame(callback) {

281

const requestRef = useRef();

282

283

useEffect(() => {

284

const animate = () => {

285

callback();

286

requestRef.current = raf(animate);

287

};

288

requestRef.current = raf(animate);

289

290

return () => {

291

if (requestRef.current) {

292

raf.cancel(requestRef.current);

293

}

294

};

295

}, [callback]);

296

}

297

```