React.js - CodeMirror: add a keyword to SQLDialect - reactjs

my react component:
import React, { useState } from "react";
import { sql, SQLConfig, StandardSQL } from "#codemirror/lang-sql";
import CodeMirror from "#uiw/react-codemirror";
function SQLEditor() {
const config: SQLConfig = {
dialect: StandardSQL,
upperCaseKeywords: true,
};
const [command, setCommand] = useState("");
return (
<>
<CodeMirror
value={command}
extensions={[sql(config)]}
onChange={(value) => {
setCommand(value);
}}
/>
</>
);
}
export default SQLEditor;
i'm using #uiw/react-codemirror and #codemirror/lang-sql
let's say i want to add "hello" as a keyword, the same way "INSERT" and "CREATE" are keywords, so that when the user writes "hello" it will get highlighted as a keyword
how can i achieve that?

Related

How to create HOC to wrap useContext provider in React?

I want to reuse a context provider in different parts of my app using HOC ("higher order components"), but my state does not get updated.
This is the wrapper of the provider.
import React, { FC, useState } from "react";
import AdminContext from "./adminContext";
const AdminContextWrapper: FC = ({ children }) => {
const [authAdmin, setAuthAdmin] = useState<boolean | null>(null);
const value = { authAdmin, setAuthAdmin };
return (
<AdminContext.Provider value={value}>{children}</AdminContext.Provider>
);
};
export default AdminContextWrapper;
This is how I am implementing it :
import { useContext } from "react";
import AdminContext from "#comp/contexts/adminContext";
import AdminLogin from "#comp/admin/adminLogin";
import Limit from "#comp/admin/limits";
import AdminContextWrapper from "#comp/contexts/adminWrapper";
const Admin = () => {
const { authAdmin } = useContext(AdminContext);
const AdminPage = () => {
return (
<div>
<Limit />
</div>
);
};
return (
<AdminContextWrapper>
{authAdmin ? <AdminPage /> : <AdminLogin />}
</AdminContextWrapper>
);
Finally, this is my context:
import { createContext } from "react";
import { AdminContextType } from "#comp/utils/types";
const InitialUserContext: AdminContextType = {
authAdmin: false,
setAuthAdmin: (authAdmin: boolean | null) => {},
};
const AdminContext = createContext<AdminContextType>(InitialUserContext);
export default AdminContext;
I can see the state change in the login page but the admin page is not getting the update.
adminLogin.tsx
//...
const { setAuthAdmin, authAdmin } = useContext(AdminContext);
useEffect(() => {
console.log(authAdmin); // returns true after validating but the admin does not update.
}, [authAdmin]);
//...
I highly appreciate any help. Thank you.
Unless I'm misreading things, in
const Admin = () => {
const { authAdmin } = useContext(AdminContext);
// ...
return (
<AdminContextWrapper>
{authAdmin ? <AdminPage /> : <AdminLogin />}
</AdminContextWrapper>
);
}
you're trying to use the context outside its provider AdminContextWrapper - useContext would return undefined there unless you're already nested within another provider for the admin context, in which case the inner AdminContextWrapper there would give the inner components a different admin context.
You may want to make sure there's only ever exactly one admin context.
(As an aside, the // ... above used to be a nested component in your original code. Never do that – nested components' identity changes on each update, causing spurious re-renders.)

React Select Control

I have data in a file named GlobalState.js and I am trying to access it another file named AddClass.js.
GlobalState.js
myclasses:[
{
"id":"class1",
"name":"Maths",
"students":["arun1","ashok1","rajesh1","mahesh1"],
"teachers":["ramesh1","suresh1","ashwin1"]
},
{
"id":"class2",
"name":"Science",
"students":["arun2","ashok2","rajesh2","mahesh2"],
"teachers":["ramesh2","suresh2","ashwin2"]
}
]
I want the students names to be shown on my React-Select control. Below is the code that I tried. Thank you for the support.
AddClass.js
import React, {useState, useEffect, useContext } from 'react'
import { GlobalContext } from '../../context/GlobalState'
import { v4 as uuid } from "uuid";
import { useForm } from "react-hook-form";
import { Link, useHistory } from 'react-router-dom';
import Select from 'react-select'
const AddClass = () => {
const [selectedOption, setSelectedOption] = React.useState();
const { addClass, myclasses} = useContext(GlobalContext);
const studOptions = myclasses.map((c)=> {
return {label:c.students.map((s)=>{
console.log("s",s)
return([{value: s, label:s}]);
}), value:c.id}
})
return (
<React.Fragment>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Select Students</label>
<Select
value={selectedOption}
isMulti
onChange={handleChange}
options={filteredStud}
/>
</form>
</React.Fragment>
)
}
export default AddClass
To get all the students in all classes and put them to one select options, your code should do something like below:
const options = myclasses.map(c => c.students).flat().map(s => ({ label: s, value: s}))
I would make studOptions a state, extract data from myclasses to populate into studOptions, then display it into the select.
Sample: https://codesandbox.io/s/affectionate-liskov-5k6l4?file=/src/App.js

React native typescript: usecontext functions not firing from inside child component

I have an issue when i try to use functions from a context inside a child component in a React native android app.
Below is my code for the context, and the form component im using it in (stripped down for brevity).
The "isFormOpen" object can be read no problem from inside any children that is wrapped in the provider, but when i try to call the "toggleForm" function from the same child component, it does nothing, no console errors either.
I have another context which is identical in structure and syntax except for vairable and function names etc, and that works perfectly, so im a bit confused as to why this does not work. I removed the other context, thinking there might be some type of conflict, but didnt solve it.
AccountContext.tsx
import React, { FC, createContext, useContext, useState } from 'react';
interface AccountContextType {
isFormOpen: boolean,
toggleForm: (toggle: boolean) => void
};
export const AccountContext = createContext<AccountContextType>({
isFormOpen: false,
toggleForm: () => null
});
export const AccountContextProvider: FC = props => {
const [formOpen, setFormOpen] = useState<boolean>(false);
const toggleForm = (toggle: boolean) => {
setFormOpen(toggle);
}
const value: AccountContextType = {
isFormOpen: formOpen,
toggleForm
}
return (
<AccountContext.Provider value={value}>
{props.children}
</AccountContext.Provider>
)
}
export const useAccountContext = () => useContext(AccountContext);
TrackUploadForm.js
import React from 'react';
import { SafeAreaView } from 'react-native';
import { Button } from 'react-native-paper';
import { useAccountContext } from '../contexts/AccountContext';
import { AccountContextProvider } from '../contexts/AccountContext';
const TrackUploadForm = () => {
const accountContext = useAccountContext();
return (
<AccountContextProvider>
<SafeAreaView>
<Button onPress={() => accountContext.toggleForm(false)} mode='outlined'>Cancel</Button>
</SafeAreaView>
</AccountContextProvider>
)
};
export default TrackUploadForm;
useAccountContext is called outside the provider
export default function App() {
return (
<AccountContextProvider>
<Content />
</AccountContextProvider>
);
}
const Content = () => {
const accountContext = useAccountContext();
return (
<div className="App">
<h1>{accountContext.isFormOpen ? "true" : "false"}</h1>
<Button onPress={() => accountContext.toggleForm(false)} mode='outlined'>Cancel</Button>
</div>
);
};
accountContext.toggleForm(false) <-- always false, change it to accountContext.toggleForm(!accountContext.isFormOpen)
Together we have
https://codesandbox.io/s/cranky-panini-yo129

unable mapping through import react components using hooks

Im new to react so this may be a noob question.
Im trying create a side bar that only displays links depending on if a variable is set.
but first im just trying to create a useState hook that is an array of import components and map through them with some dummy data.
The problem is it keeps tell me the component is undefined when trying to map through them.
error:TypeError: Cannot read property 'SideBarLink' of undefined
What am I doing wrong?
Also if there is a better way to do what I am trying to please lmk.
SideBar.jsx------------------------------------------------------
]
import React, { useState } from 'react';
import SideBarLink from 'react';
const SideBar = () => {
const [sidelinks, setSideLinks] = useState( SideBarLink[
{
id: 1,
name: 'Projects',
displayLink: true
},
{
id: 2,
name: 'Tickets',
displayLink: true
}
]);
const handleClick =() =>
{
console.log(sidelinks);
}
let slinks = (
<div>
<button onClick={handleClick}>button</button>
<div className="w3-sidebar w3-bar-block" >
{
sidelinks.SideBarLink.map((SideBarLink, index) =>
{
return <SideBarLink />
})
}
</div>
</div>
);
return slinks;
}
export default SideBar;
SideBarLink.jsx-------------------------------------
import React from 'react';
const SideBarLink = ( props ) => {
return (
{props.name}
)
};
export default SideBarLink;

React-Intl How to use FormattedMessage in input placeholder

I'm unsure how to get the values from
<FormattedMessage {...messages.placeholderIntlText} />
into a placeholder format like input:
<input placeholder={<FormattedMessage {...messages.placeholderIntlText} />} />
as it would return [Object object] in the actual placeholder. Is there a way to get the actual correct value?
The <Formatted... /> React components in react-intl are meant to be used in rendering scenarios and are not meant to be used in placeholders, alternate text, etc. They render HTML, not plain text, which is not useful in your scenario.
Instead, react-intl provides a lower level API for exactly this same reason. The rendering components themselves use this API under the hoods to format the values into HTML. Your scenario probably requires you to use the lower level formatMessage(...) API.
You should inject the intl object into your component by using the injectIntl HOC and then just format the message through the API.
Example:
import React from 'react';
import { injectIntl, intlShape } from 'react-intl';
const ChildComponent = ({ intl }) => {
const placeholder = intl.formatMessage({id: 'messageId'});
return(
<input placeholder={placeholder} />
);
}
ChildComponent.propTypes = {
intl: intlShape.isRequired
}
export default injectIntl(ChildComponent);
Please note that I'm using some ES6 features here, so adapt according to your setup.
You can use intl prop from injectIntl HoC
You can also provide function as child component:
<FormattedMessage {...messages.placeholderIntlText}>
{(msg) => (<input placeholder={msg} />)}
</FormattedMessage>
It's july 2019 and react-intl 3 beta is shipped with a useIntl hook to make these kind of translations easier:
import React from 'react';
import {useIntl, FormattedDate} from 'react-intl';
const FunctionComponent: React.FC<{date: number | Date}> = ({date}) => {
const intl = useIntl();
return (
<span title={intl.formatDate(date)}>
<FormattedDate value={date} />
</span>
);
};
export default FunctionComponent;
And then you can make custom hooks to use the methods provided by the API:
import { useIntl } from 'react-intl'
export function useFormatMessage(messageId) {
return useIntl().formatMessage({ id: messageId })
}
For Input placeholder for more details
<FormattedMessage id="yourid" defaultMessage="search">
{placeholder=>
<Input placeholder={placeholder}/>
}
</FormattedMessage>
As from React version >= 16.8, you can use useIntl hook :
import React from 'react';
import { IntlProvider, useIntl } from 'react-intl';
const FunctionComponent = () => {
const intl = useIntl();
const lang = "en";
const messages = {
en: {
'placeholderMessageId': 'placeholder in english',
},
fr: {
'placeholderMessageId': 'placeholder en fançais',
}
}
return (
<IntlProvider locale = {lang} messages = { messages[lang] } >
<input placeholder = { intl.formatMessage({ id: 'placeholderMessageId' })}/>
</IntlProvider >
);
};
export default FunctionComponent;
Based on the react intl wiki the implementation of an input box with translatable placeholder will look like:
import React from 'react';
import { injectIntl, intlShape, defineMessages } from 'react-intl';
const messages = defineMessages({
placeholder: {
id: 'myPlaceholderText',
defaultMessage: '{text} and static text',
},
});
const ComponentWithInput = ({ intl, placeholderText }) => {
return (
<input
placeholder={ intl.formatMessage(messages.placeholder, { text: placeholderText }) }
/>
);
};
ComponentWithInput.propTypes = {
intl: intlShape.isRequired
};
export default injectIntl(ComponentWithInput);
and the useage of it:
import ComponentWithInput from './component-with-input';
...
render() {
<ComponentWithInput placeholderText="foo" />
}
...
The id: 'myPlaceholderText', part is necessary to enable the babel-plugin-react-intl to collect the messages for translation.
I would like to suggest this solution :
import { useIntl } from "react-intl";
export default function MyComponent() {
const intl = useIntl();
return (
<input placeholder={intl.formatMessage({ id: "messageId" })} />
);
}
You are trying to render a React component named FormattedMessage into a placeholder tag which is expecting a string.
You should instead just create a function named FormattedMessage that returns a string into the placeholder.
function FormattedMessage(props) {
...
}
<input placeholder=`{$(FormattedMessage({...messages.placeholderIntlText})}` />
Consider this possibility.
The simplest solution
<IntlMessages id="category.name">
{text => (
<Input placeholder={text} />
)}
</IntlMessages>
OR
In my case I had the whole app in one file, so using export wouldn't work. This one uses the normal class structure so you can use the state and other functionality of React if needed.
class nameInputOrig extends React.Component {
render () {
const {formatMessage} = this.props.intl;
return (
<input type="text" placeholder={formatMessage({id:"placeholderIntlText"})} />
);
}
}
const nameInput = injectIntl(nameInputOrig);
Apply using the created constant:
class App extends React.Component {
render () {
<nameInput />
}
}
Starting from the #gazdagerg 's answer, I have adapted his code in order to:
having a new component that is a wrapper over an input
receives an ID of a string from locale conf
based on the ID, it returns the string in respect to the global locale setting
handling the situation when the string ID is not set (this caused exception and page to crash)
import React from 'react';
import { injectIntl, intlShape, defineMessages } from 'react-intl';
const InputWithPlaceholder = ({ intl, placeholder }) => {
const messages = defineMessages({
placeholder: {
id: placeholder,
defaultMessage: '',
},
});
if(messages.placeholder.id) {
return (
<input placeholder={ intl.formatMessage(messages.placeholder) } />
);
} else {
return (
<input/>
);
}
};
InputWithPlaceholder.propTypes = {
intl: intlShape.isRequired
};
export default injectIntl(InputWithPlaceholder);
You can use it in other file by:
import the new component
use it with the ID of the locale string as parameter
import InputWithIntlPlaceholder from 'your/path/to/component/InputWithIntlPlaceholder';
... more code here ...
<InputWithIntlPlaceholder placeholder="your.locale.string.id" />
Like this:
import React, {PropTypes} from 'react';
import { injectIntl, FormattedMessage } from 'react-intl';
 
/**
* {
* "hello": "Hello",
* "world": "World"
* }
*/
 
// pure function
const PureFunciton = injectIntl(({ intl }) => {
return (
<div>
<p>{intl.formatMessage({ id: 'hello' })}</p>
<p><FormattedMessage id="world" /></p>
</div>
)
});
 
// class Component
class componentName extends Component {
handleStr = () => {
// return 'Hello';
const { intl } = this.props;
return intl.formatMessage({ id: 'hello' })
}
render() {
return (
<div>
<p>{this.handleStr()}</p>
<p><FormattedMessage id="world" /></p>
</div>
);
}
}
 
export default injectIntl(connect(componentName));

Resources