Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to "dynamically" connect to different states with React/Preact? #195

Open
rmorse opened this issue Jun 11, 2021 · 1 comment
Open

How to "dynamically" connect to different states with React/Preact? #195

rmorse opened this issue Jun 11, 2021 · 1 comment

Comments

@rmorse
Copy link

rmorse commented Jun 11, 2021

I see that connect can be used like this:

connect( [ 'var1', 'var2' ], actions )

Which works well... however I want to init a component, and pass the state name into it somehow...

The problem: I have a store, which based on user interaction (from the dom) will create a new state object eg state.field_${id}, and then dynamically render a Preact component... I want to pass down the state name / ID into a preact component/wrapper so it can connect to its own state object - field_${id},

The only thing I can think of, is to just connect it to the whole state, pass in the ID, and then filter that out manually...

const allState = ( state ) => {
	return state;
};
export const MyComponent = connect(
	allState,
	actions
)( ( props ) => {
        const myState = props[ `field_${ props.id }` ];
	return <>...</>;
} );

But it doesn't sit right with me, and the component would naturally re-render on any state change rather the part we're after... .

Is this possible / are there any other approaches I might have missed?

Thanks!

@rmorse
Copy link
Author

rmorse commented Jun 11, 2021

Ok so I might have answered my own question.

I had a peek at the connect function and stole some ideas from there.

What I've done:

  1. Create a new context (the context is not exposed in unistore/preact) and ensure to pass the store as a prop to the provider
  2. Wrap this around the app just like unistore/preact
  3. Then use the useContext hook to supply the store to the component
  4. Update local state to keep track of the updates and trigger re-renders
  5. Wrap as a HOC

const StoreContext = createContext( {} );
// Make sure a StoreContext Provider is around the app

const getStateByKey = ( state, key ) => {
	return state[ key ] ?? null;
};

const withStoreKey = ( WrappedComponent ) => ( { storeKey, ...rest } ) => {
	const store = useContext( StoreContext );
	const [ localState, setLocalState ] = useState(
		getStateByKey( store.getState(), storeKey )
	);
	const receiveState = ( state ) => {
		setLocalState( getStateByKey( state, storeKey ) );
	};
	useEffect( () => {
		store.subscribe( receiveState );
		return () => {
			store.unsubscribe( receiveState );
		};
	}, [] );

	if ( localState === null ) {
		return null;
	}
	return ( <WrappedComponent { ...localState } { ...rest } /> );
};

So now I can do:

const MyComponent = () => {
	return <div>Hello wrld</div>;
};
const MyConnectedComponent = withStoreKey( MyComponent );
const App = () => {
	return <MyConnectedComponent storeKey={ 'customStoreKey' } more={ 'props' } />;
};

Using this method, I don't need to import unistore/preact and can designate specific props from a store's state to specific components...

Open to any suggestions of doing this another way but I think I'm quite happy with this implementation :)

@rmorse rmorse changed the title How to "dynamically" connect to different states? How to "dynamically" connect to different states with React/Preact? Jun 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant