跳到主要内容

Use Namespaced Provider

This tutorial will guide you on how to use the namespaced provider. We’ll create a simple survey with two steps. In the first step, you’ll select a gender. The second step will display content based on the gender selected in the first step. For simplicity, the second step will only show the selected gender.

Setup

Add Houp in you project.

npm install houp

Add <Provider />

Add <Provider /> at the top of your App.

src/index.tsx
import { Provider } from "houp";
import React, { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const rootElement = document.getElementById("root")!;
const root = ReactDOM.createRoot(rootElement);

root.render(
<StrictMode>
<Provider />
<App />
</StrictMode>
);

Register a global store

Create a hook in src/useSurveyPanel.ts and register it as a global store to manage the visibility of the survey panel.

src/useSurveyPanel.ts
import { registerStore } from "houp";
import { useState } from "react";

export default function useSurveyPanel() {
const [show, setShow] = useState(false);

return {
show,
setShow,
};
}

registerStore(useSurveyPanel);

Register a store with a namespace

Create a hook in src/useSurvey.ts and register it under the survey namespace. This store will be used in the survey component.

src/useSurvey.ts
import { registerStore } from "houp";
import { useState } from "react";

export type Survey = {
step: "first" | "second";
gender: "male" | "female";
};

export default function useSurvey() {
const [survey, setSurvey] = useState<Survey>({
step: "first",
gender: "male",
});

return {
survey,
setSurvey,
};
}

registerStore(useSurvey, "survey");

Create the Survey component

Create the Survey component in src/survey.tsx, which contains two child components: FirstStep and SecondStep. The FirstStep component allows you to choose a gender, while the SecondStep displays the selected gender.

The SecondStep includes a 'Previous' button. When clicked, it returns you to the FirstStep, and the gender choice is preserved because it is saved in the useSurvey store.

Clicking the 'Done' button in the SecondStep component will close the survey.

src/survey.tsx
import { useStore } from "houp";
import useSurvey from "./useSurvey";
import useSurveyPanel from "./useSurveyPanel";

function FirstStep() {
const store = useStore(useSurvey);

const setGender = (gender: "male" | "female") => {
store.setSurvey((state) => ({ ...state, gender }));
};

return (
<div>
Choose your gender:
<label style={{ display: "block" }}>
<input
type="radio"
name="gender"
value="male"
defaultChecked={store.survey.gender === "male"}
onChange={(e) => setGender(e.target.value as "male" | "female")}
/>
Male
</label>
<label style={{ display: "block" }}>
<input
type="radio"
name="gender"
value="female"
defaultChecked={store.survey.gender === "female"}
onChange={(e) => setGender(e.target.value as "male" | "female")}
/>
Female
</label>
<button
onClick={() =>
store.setSurvey((state) => ({ ...state, step: "second" }))
}
>
Next
</button>
</div>
);
}

function SecondStep() {
const store = useStore(useSurvey, (state) => ({
gender: state.survey.gender,
setSurvey: state.setSurvey,
}));
const panelStore = useStore(useSurveyPanel);

return (
<>
<div>Gender: {store.gender}</div>
<button
onClick={() =>
store.setSurvey((state) => ({ ...state, step: "first" }))
}
>
Previous
</button>
<button onClick={() => panelStore.setShow(false)}>Done</button>
</>
);
}

export default function Survey() {
const store = useStore(useSurvey);

return (
<>
<div>
<span>----</span>
<b
style={{
color: store.survey.step === "first" ? "green" : "gray",
}}
>
Step 1
</b>
<span>-----------------------</span>
<b
style={{
color: store.survey.step === "second" ? "green" : "gray",
}}
>
Step 2
</b>
<span>----</span>
</div>
{store.survey.step === "first" && <FirstStep />}
{store.survey.step === "second" && <SecondStep />}
</>
);
}

Add the Survey component to the App

Clicking the 'Begin' button will display the survey, and the button will remain hidden until you click the 'Done' button in the survey.

src/App.tsx
import { Provider, useStore } from "houp";
import Survey from "./survey";
import "./styles.css";
import useSurveyPanel from "./useSurveyPanel";

export default function App() {
const store = useStore(useSurveyPanel);

if (!store.show) {
return <button onClick={() => store.setShow(true)}>Begin</button>;
}
return (
<>
{store.show && (
<>
<Provider namespace="survey" />
<Survey />
</>
)}
</>
);
}
提示

Each time you complete the survey, the namespaced provider <Provider namespace="survey" /> will be unmounted. When you click 'Begin' again, a new useSurvey store will be created.

Full Example

Here’s the complete survey application, running on CodeSandbox.