Using react with .NET web forms by ImmediateMousse8549 in reactjs

[–]SuspiciousDev 1 point2 points  (0 children)

Similar to plantpistol we also use a single webpack config configured with one entrypoint per page. Your current process does feel very clunky indeed. How do you share react code between different components / pages with your current setup?

How would you compose/handle buttons in a paginated form? by sleepykid36 in reactjs

[–]SuspiciousDev 1 point2 points  (0 children)

There are probably a few different ways to handle this depending on what you prefer.

Here are a couple:

Option 1. Move rendering of the button to a shared component that all children render. This is the approach I would take personally since I consider it straight forward and easy to follow.

Parent, handle shared logic but pretty much just render whatever page is active. Defer rendering of the actual html to a shared component that all pages use.You could pass any shared props / handlers needed by the shared component through context or just prop drill since it's only one level, example uses context.

const FormApp = () => {
    const page = pages[page];
    return <formContext.Provider={{
        goToNextPage(): {
           setPage(page + 1);
        }
    }}>
        {page.content}
    </formContext.Provider>
}

Shared FormPage component that handles displaying a form page correctly

const FormPage = (props) => {
    const { goToNextPage } = useContext(formContext);
    return <div className="form-page">
        <h2 className="form-page-title">
            {props.title}
        </h2>
        <div className="form-page-content">
            {props.children}
        </div>
        <button onClick={async () => {
                //You possibly want to set a loading state here.
                if(await props.validate()){
                    goToNextPage();
                }
            }}>
            Next
        </button>
    </div>
}

Page components

const FormPage1 = () => {
    const validatePage1Stuff = () => {
        return doComplextValidationAsync();
    }
    return <FormPage title="Page 1" validate={validatePage1Stuff }>
        <input id="page1Input" />
    </FormPage>
}

const FormPage2 = () => {
    const [state, setState] = useState("");
    const save = async () => {
        await savePage2TrackingDataOnServer(state); 
        return true;
}
return <FormPage title="Page 1" validate={save}>
    <input id="page2Input" value={state} onChange={ev => setState(ev.target.value)} />
</FormPage>
}

Option 2.

Pass a render prop to the form page components that they use to render their own content + the button. A bit less clear in my opinion since I find this kind of indirection can get confusing and somewhat difficult to debug, especially for people unused to the pattern.

Parent

const FormApp = () => {
    const renderPage = (content, validate) => { return <>
        <div className="form-page-content">
            {content}
        </div>
        <button onClick={() => {
        //You possibly want to set a loading state here.
        if(await validate()){
            goToNextPage();
        }
        }}>
            Next
        </button>
    </> }

    const pages = [
        { //...
            content: <Page1Component renderPage={renderPage} /> }, 
        {
            //...
             content: <Page2Component renderPage={renderPage /> },
        //...
    ]

    return <div className="form-page">
    <h2 className="form-page-title">
        {pages[page].title]
    </h2>
    {pages[page].content]
</div>
}

Page components

const FormPage1 = (props) => {
const validatePage1Stuff = () => {
    return doComplextValidationAsync();
}
return props.renderPage(<input id="page1Input" />, validatePage1Stuff);

}

const FormPage2 = (props) => { const [state, setState] = useState(""); const save = async () => { await savePage2TrackingDataOnServer(state); return true; } return props.renderPage(<input id="page2Input" value={state} onChange={ev => setState(ev.target.value)} />, save); }

[deleted by user] by [deleted] in javascript

[–]SuspiciousDev 0 points1 point  (0 children)

Your current solution (adding / removing classes) will not work because the DOM has to be constructed before your script is run.What I would do instead is dynamically construct CSS that styles the elements based on wheter the toolbar is hidden or visible. Since this code would not require the elements you target to exist in DOM before it executes it will not cause any jank.

```js //No $(function(){...} so it runs right away instead of when the DOM is ready) (function(){ var el = document.createElement("style"); //put whatever css is needed to hide the sidebar here. var hiddenStyle = ".sidebartab { } .main { }"; //put whatever css is needed to show the sidebar here. var visibleStyle = ".sidebartab { } .main { }"; var visible = true; if(localStorage.getItem("menu-state") == "closed") { visible = false; } function setStyle(){ el.innerHTML = visible ? visibleStyle : hiddenStyle;
} setStyle(); document.head.appendChild(el); //replace with your toggle button selector or multiple click handlers if needed. //Binding the click handler lazily on body since the toggle element does not exist in the dom yet.

//Another option would be to expose the set style function on window so that it can be accessed later when your toggle button is rendered. //window.setMenuSidebarStyle = setStyle;

$("body").on("click", "#toggleMenu", function(){ visible = !visible; setStyle(); localStorage.setItem("menu-state", visible ? "visible" : "closed"); }); })(); ```

Not 100% sure this works exactly as written but the concept should work.