0.4.1 • Published 6 months ago

make-list-provider v0.4.1

Weekly downloads
-
License
MIT
Repository
github
Last release
6 months ago

Make List Provider

Do you have a React hook that you need to call some number of times? Would you like to use React hooks to replace your list of classes with react natively? Do you just really like using lots of hooks and need to keep their output in a list?

Make a react list provider to store hook states and actions.

Usage

const [Provider, useItem, useList] = makeListProvider();

Provider

Provider for the list

  • onChange: called with a copy of a list when it is changed
return (
	<Provider
		onChange={setList}
	>
		<Component name="1" />
		{more.map(id => (
			<Component key={id} name={id} />
		))}
	</Provider>
);

useItem

Creates an entry in the Provider's list. Any value can be supplied as the argument. Changes to the value will update the Provider's callback and useList hook.

For ordered providers, useItem will return the index of the item in the ordered list.

export function Component({ name }) {
	const [state, setState] = useState(() => Math.random());

	const index = useItem(useMemo(() => ({
		name,
		state,
		setState,
	}), [name, state]));

	return null;
}

useList

Returns the Provider's list of values.

export function useItemByName(name) {
	const list = useList();
	const item = list.find(item => item.name === name);
	return item;
}

Variants

listProvider

The listProvider variant is the default behavior. The list is ordered based on React's useLayoutEffect call order. This is very useful for executing functions generated by JSX in order like layering on a Canvas.

const [CanvasProvider, useDraw, useDrawList] = makeListProvider();

function RenderCanvas() {
	const drawCallbacks = useDrawList();
	// ...
	return <canvas ref={ref} />
}

function DrawBox(props) {
	// ...
	useDraw(drawCallback);
}

function App() {
	return (
		<CanvasProvider>
			<RenderCanvas />
			<DrawBox rect={[1,2]} />
			<DrawBox rect={[2,3]} />
		</CanvasProvider>
	);
}

unorderedProvider

The unorderedProvider variant performs all the above functions without any ordering to the items. These will appear in any order they are called by React and are uncontrolled. This is useful for something like tracking many socket connections or local storage states.

const [SocketsProvider, useSocket, useSocketList] = makeUnorderedProvider();

function useSocketByName(name) {
	return useSocketList().find(socket => socket.name === name);
}

function Socket(props) {
	// ...
	useSocket(socket);
}

function App() {
	return (
		<SocketsProvider>
			<Socket port={8080} />
			<Socket port={8081} />
		</SocketsProvider>
	);
}

domProvider

The domProvider variant orders items based on the DOM subtree. A ref must be provided to each useItem as well as a parentRef to the Provider to observe updates. Using the DOM instead of the render cycle can reduce cpu usage on rarely changed elements. This is useful for custom select/option components

const [OptionsProvider, useOption, useOptionList] = makeDomProvider();

function Option(props) {
	const options = useOptionList();
	// ...
	const index = useOption(ref, value);
	return (
		<option ref={ref}>{index}</option>
	);
}

function App() {
	return (
		<select ref={ref}>
			<OptionsProvider parentRef={ref}>
				<Option />
				<Option />
			</OptionsProvider>
		</select>
	);
}

Notes

Ordering Children

Per useLayoutEffect's call order, a parent element will be ordered after it's children. To avoid unexpect results, you should not nest children under an element that is calling useItem. This behavior may change in the future.

Note: useLayoutEffect is used only in useListProvider. If you need more DOM driven ordering, try useDomProvider.

function Item({ children }) {
	useItem();
	return children;
}

function App() {
	return (
		<Provider>
			<Item />	// 1
			<Item>	// 3
				<Item />	// 2
			</Item>
			<Item />	// 4
		</Provider>
	);
}

License

Copyright (c) 2021, Michael Szmadzinski. (MIT License)

0.3.0

6 months ago

0.4.1

6 months ago

0.4.0

6 months ago

0.2.2

3 years ago

0.2.1

3 years ago

0.2.0

3 years ago

0.1.0

3 years ago