It's possible to change the header for a custom component? (react navigation) - react-navigation

I am using reaction navigation, I would like to have my own header component (it is very specific).
In the publication it says that it is possible to change the title or the title of something personalized, but is it possible to change the header for another component?
I thought about doing something like that
<App.Screen
name="Scan"
component={Scan}
options={{ header: (props) => <MyCustomComponent {...props} /> }}
/>

Related

Do not use built-in or reserved HTML elements with Vue, TailwindUI and Headless UI

I'm trying to add the TailwindUI / Headless UI Menu (dropdown) to Vue and am getting two errors in the console:
Do not use built-in or reserved HTML elements as component id: menu
and
Error: < MenuButton /> is missing a parent < Menu /> component
I'm Using Vue 3 within a Laravel 8 app, here's what app.js looks like:
import { Menu, MenuButton, MenuItems, MenuItem } from "#headlessui/vue";
const app = createApp({
...
});
app.component('menu', Menu);
app.component('menubutton', MenuButton);
app.component('menuitems', MenuItems);
app.component('menuitem', MenuItem);
app.mount("#app");
And here's a minimal example for the view:
<Menu>
<MenuButton>More</MenuButton>
<MenuItems>
<MenuItem v-slot="{ active }">
<a :class='{ "bg-blue-500": active }' href="/test">
Test
</a>
</MenuItem>
</MenuItems>
</Menu>
I've tried everything that I can think of and am lost! Any ideas?
Do not use <Menu>-element as it is a built-in HTML element.
Just rename to something like CustomMenu
import { Menu as CustomMenu, ... } from ...
app.component('menu', CustomMenu);
<CustomMenu>
...

Manually trigger validations(Validate Formik Form ) on button click even when fields are untouched

In our React app, We have multiple forms in a page. We use Formik and Yup for forms and validations respectively
Currently validations are fired only when field/form are touched. We have build wrapper on Formik that submits form on blur/focus out event.
Now, the requirement is to show error for all the required fields in a page that includes multiple Formik forms on click of a button.
To clarify further, my wrapper looks like
const { onSubmit, className, style, ...restProps } = this.props;
return (
<div
ref={this.setContainerRef}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
tabIndex={-1}
className={className}
style={style}
>
<Formik
{...restProps}
ref={this.setFormikRef}
initialValues={this.props.currentValues}
validateOnBlur={true}
validateOnChange={false}
render={(formikProps: FormikProps<T>) => (
<>
<DirtyFormReporter onChange={this.handleDirtyFormReport} isDirty={formikProps.dirty} />
{this.props.render(formikProps, this.createEditBlurFormActions())}
</>
)}
onSubmit={this.handleSubmit}
/>
{ReactDOM.createPortal(<InputBlocker text="Updating" isEnabled={this.state.isSubmitting} />, document.body)}
</div>
);
There are multiple ways to handle this situation but you can use fieldarray of Formik here.
https://formik.org/docs/api/fieldarray
When you will submit you will get an array and a list of forms in it then you can simple add and remove forms and you can easily do your validation using Yup.

Formik Form validation in react

I have implemented form validation with formik and react. I am using material-UI.
<Formik
initialValues={{ name: '' }}
onSubmit={values => {
console.log('submitting', values);
}}
validate={values => {
alert();
let errors = {};
if (!values.name) {
errors.name = 'Name is required';
}
return errors;
}}>
{({
handleSubmit,
handleChange,
values,
errors
}) => (
<form onSubmit={handleSubmit}>
<div>
<input name="name"
onChange={handleChange}
name="name"
value={values.name}
type="text"
placeholder="Name">
</input>
{errors.name &&
<span style={{ color: "red", fontWeight: "bold" }}>
{errors.name}
</span>
}
</div>
<div>
<button>Submit</button>
</div>
</form>
)}
</Formik>
Above code is working fine for normal input tags but it is not working for Select and TextField material widgets.
Is there a compatibility issue with material UI ?
Please help.
As Chris B. commented, the solution is to wrap each desired element inside a React component that has what Formik requires. In the case of Material-UI, Gerhat on GitHub has created some of those components.
You can use those by downloading the source from the github link above. There is also a usage example there, showing how to use Gerhat's "wrapper" for a Material TextField and a Select.
In Gerhat's usage example, TextField is a component in that github repo; it isn't the Material UI TextField directly; it is a Formik-compatible "wrapper" around the Material TextField widget.
By looking at gerhat's source code, you can learn how to do the same for other Material widgets you need.
HOWEVER, gerhat's implementation may not be the easiest for a beginner to understand. Those wrappers are easy to use, but it may not be obvious from that code how to write your own wrappers for other widgets or components.
See my answer here for a discussion of Formik's <Field> and useField. Those are easier ways to "wrap" existing React components. (Not specifically Material-UI widgets, but AFAIK, you can wrap those like any other React component.)
If you do want to understand gerhat's approach, here are some comments about the code you'll see at github.
This is the source to TextField.jsx in that repo.
The "heart" of TextField.jsx, is its wrapping around Material's TextField. The generated virtual-DOM element (representing a Material TextField) is seen in these lines:
return (
<TextField
label={label}
error={hasError}
helperText={hasError ? errorText : ''}
{...field}
{...other}
/>
)
See the source link above, for the details of how this is made compatible with Formik. IMHO, a fairly advanced understanding of both React and Formik is required, to understand what is being done there. This is why I mentioned Field and useField as the place to start, for writing your own "Formik-compatible wrappers".
One detail I'll mention. The implementation relies on a file index.js in the same folder as TextField.jsx, to map the default of TextField.jsx, which is FTextField, to the name TextField, which is how you refer to it in the "usage" code at the start of this answer. SO Q&A about index.js file of a React component.
index.js contents:
export { default as TextField } from './TextField'
The other two files in the TextField source folder are ".d.ts" files. See this Q&A to understand those. You don't need them unless you are using TypeScript.

Change 404 page in vuepress

Is it possible to change / customize the 404 page of Vuepress without ejecting and having to change the whole theme?
I am currently using the enhanceApp.js, but I'm unsure how I can change the router options (the catchall route) as the Router is already created. The way I got it working right now is this:
router.beforeEach((to, from, next) => {
if (to.matched.length > 0 && to.matched[0].path === "*") {
next("/404.html");
} else {
next();
}
});
However, this feels like a hack as I always redirect to a custom and existing page containing my 404. Is there a more official way to do this?
I have a site based on Vuepress 1.5.x, and I was able to simply create a page named NotFound.vue under theme/layouts. No enhanceApp.js changes needed.
Vuepress itself seems already aware of this reserved layout name, based on the code here.
I previously had that page named 404.vue, but I was getting a warning saying that pages should follow proper HTML 5 component naming standards. Simply renaming it to NotFound.vue did the trick.
Contents of my NotFound.vue file:
<template>
<BaseLayout>
<template #content>
<v-container class="text-center">
<div class="py-6" />
<h1>Oops!</h1>
<p>Nothing to see here.</p>
<v-btn class="cyan--text text--darken-3"
exact :to="'/'" text>Go home</v-btn>
</v-container>
</template>
</BaseLayout>
</template>
<script>
export default {
name: "NotFound"
};
</script>

call to ReactJS component in Laravel blade templates

I use Laravel 5.4 and React 15.5.4, code is writing in ES6.
I'd like replace Vue and use React and I did it. But I often will use small components for example 2 in different places of blade template. I don't want use one app component.
I'd like use something like:
<span class="react">
<TestComponent property={true} />
</span>
I can't do it automatically. Now I use
<span data-component="TestComponent" data-props="{property:true}" />
and in app.js
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
if(item.name !== 'data-react'){
element.removeAttribute(item.name);
}
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works but I need to use add all properties to one react component property and then use for example this.props.out.propery
I also would like set normal component tag in my blade component
I've try to use in app.js
_.each(document.querySelectorAll('.react'), item => {
ReactDOM.render(item.children,item);
});
Someone have any idea to solve this problem?
EDIT
I changed my solution to:
<span data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
or
<LoginForm data-react="LoginForm" input="{{json(request()->old())}}" error="{{session('error')}}" errors="{{json($errors->getMessages())}}" />
in blade and in resources/assets/js/app.js
var reactComponents = {
LoginForm: require('./components/login').default,
};
_.each(document.querySelectorAll('[data-react]'), element => {
let props ={};
Array.prototype.slice.call(element.attributes)
.forEach(item => {
props[item.name] = item.value;
});
ReactDOM.render(React.createElement(reactComponents[element.getAttribute('data-react')],props),element);
});
It works fine. This is not super clear solution but I have impression that the reasonable.
I can set components name in html code and add props almost same like in JSX.
As far as I know, you can not mix JSX components directly with Blade templates. The only server side rendering available today for React is NodeJS.
What you could do to improve your architecture is add specific HTML tags with certain ids and render the react components in them. So inside Blade you could do something like:
<div id="componentA"></div>
This will act as a place holder in your Blade template for that react component. Then you render your componentA from your app.js like this:
React.render(<ComponentA prop1='valueX'/>, document.getElementById("componentA"))
Remember that in this case the world of react and world of Blade run at different times.
You could use document.getElementsByTagName('LoginForm') getting all the instances and later iterate its attributes. It's clear code but not generic, because it will work just for LoginForm components.
If you want to render any tag name, then maybe it's better to use some attribute as you used with data-react.
getElementsByTagName isn't super supported by old browsers so maybe could a good idea to use jQuery as fallback $('LoginForm')

Resources