How to get a value from code mirror in react js? - reactjs

I am trying to get a value from the code mirror input field but I don't know why I am not getting the value from code mirror input field
import CodeMirror from "#uiw/react-codemirror";
import { markdown, markdownLanguage } from "#codemirror/lang-markdown";
import { languages } from "#codemirror/language-data";
export default function Editor() {
const [get, set] = useState("");
console.log(get); {/* doesn't display anything */}
return (
<>
<CodeMirror
value={get}
extensions={[
markdown({ base: markdownLanguage, codeLanguages: languages }),
]}
onInput={(e) => set(e.target.value)}
/>
</>
);
}

Try useEffect hook, it calls the function inside whenever variable in second argument array changes, in this specific scenario when get changes.
import CodeMirror from "#uiw/react-codemirror";
import { markdown, markdownLanguage } from "#codemirror/lang-markdown";
import { languages } from "#codemirror/language-data";
import { useEffect } from "react";
export default function Editor() {
const [get, set] = useState("");
useEffect(() => {
console.log(get) //gets called whenever get state changes
}, [get])
return (
<>
<CodeMirror
value={get}
extensions={[
markdown({ base: markdownLanguage, codeLanguages: languages }),
]}
onInput={(e) => set(e.target.value)}
/>
</>
);
}

The onChange handler can output the value as below.
import { markdown, markdownLanguage } from "#codemirror/lang-markdown";
import { languages } from "#codemirror/language-data";
import { useState } from "react";
export default function Editor() {
const [get, set] = useState("");
console.log(get);
return (
<>
<CodeMirror
value={get}
extensions={[
markdown({ base: markdownLanguage, codeLanguages: languages })
]}
onChange={(value) => set(value)}
/>
</>
);
}
Working example

Related

Error when using react context - Cannot destructure property

i trying to using Context on my react app
but i got error:
Uncaught TypeError: Cannot destructure property 'selected' of 'Object(...)(...)' as it is undefined.
in my InputsList file
on this line:
const { selected, setSelected } = useContext(ParamsContext);
ParamsContext:
import { createContext } from 'react';
export const ParamsContext = createContext({
selected: [],
setSelected: () => {},
textName: null,
valueName: null
});
InputParams:
import React, { useState } from 'react';
import InputsList from './InputsList';
import { ParamsContext } from './services/ParamsContext';
function InputParams(props) {
const [selected, setSelected] = useState([]);
const textName = "test";
const valueName = "test2";
return (
<div>
<ParamsContext.Provider
selected={selected}
setSelected={setSelected}
textName={textName}
valueName={valueName}>
<InputsList />
</ParamsContext.Provider>
</div>
);
}
export default InputParams;
InputsList:
import React, { useContext } from 'react';
import { ParamsContext } from './services/ParamsContext';
function InputsList(props) {
const { selected, setSelected } = useContext(ParamsContext);
return (
<div>
{selected.length}
</div>
);
}
export default InputsList;
what can i do?
Contexte.Provider accept a value props,
And should be used like:
<ParamsContext.Provider value={{selected, setSelected, textName, valueName}}>
<\ParamsContext.Provider>
Provider accept a value prop, in your case, an object. So it should be:
<ParamsContext.Provider
value={{
selected,
setSelected,
textName,
valueName
}}
>
<InputsList />
</ParamsContext.Provider>
See docs

Disabling a button based until data is received from the api response in react

I prepared a demo based on a project that I'm working.
Stack Blitz
I have a state variable in NewExportRequestStore as isCalculationLoadHw. isCalculationLoadHw is set to true before an api call and false after receiving the response from the api in both the methods in the NewExportRequestStore. But here I simulated it as setimeout.
import {useState} from "react";
interface INewExportRequestState
{
state:{
isCalculationLoadHw:boolean;
}
}
interface INewExportRequestStoreActions
{
actions:{
getCalDraftHW():void;
getCalDraftSW():void;
}
}
const useNewExportRequestStore = ():INewExportRequestStoreActions &
INewExportRequestState => {
const[isCalculationLoaddHw,setCalculationLoadHw] = useState(false);
const getCalDraftHW =():void=>{
setCalculationLoadHw(true);
setTimeout(() => {
setCalculationLoadHw(false);
}, 3000);
}
const getCalDraftSW =():void =>{
setCalculationLoadHw(true);
setTimeout(() => {
setCalculationLoadHw(false);
}, 3000);
}
return {
state:{
isCalculationLoadHw
},
actions:{
getCalDraftHW,
getCalDraftSW
}
}
}
export default useNewExportRequestStore;
The buttons in NewCalculation, NewSwCalculation get disabled as per the change in the state but the button in the child component NewChildSwCalculation doesn't get disabled based on the state variable.
import { useEffect } from 'react';
import useNewExportRequestStore from './Contract/NewExportRequestStore';
const NewCalculation =() =>{
const {state,actions} = useNewExportRequestStore();
useEffect(()=>{
actions.getCalDraftHW();
},[]);
return (
<div>
Hello from New Calculation.
<button disabled={state.isCalculationLoadHw?true:false}>Calculate</button>
</div>
);
}
export default NewCalculation;
NewSwCalculation.tsx
import React from "react";
import { useEffect } from "react";
import useNewExportRequestStore from "./Contract/NewExportRequestStore";
import NewChildSwCalculation from "./NewChildSwCalculation";
const SwCalculation = () =>{
const {state,actions} = useNewExportRequestStore();
useEffect(()=>{ actions.getCalDraftSW(); },[]);
return (
<div>
Hello from Software Calculation
<button disabled={state.isCalculationLoadHw}>Export</button>
<NewChildSwCalculation/>
</div>
);
}
export default SwCalculation;
NewChildSwCalculation.tsx
import React from "react";
import {useEffect} from "react";
import useNewExportRequestStore from "./Contract/NewExportRequestStore";
const NewChildSwCalculation =() =>{
const {state,actions} = useNewExportRequestStore();
return(
<div>
Hello from the Child Sw Calculation
<button disabled={state.isCalculationLoadHw}>
Export Child Sw
</button>
</div>
);
}
export default NewChildSwCalculation;
I'm unsure how to disable the button in the child component based on the isCalculationLoadHw

TypeError: Cannot read property 'onMonthSelect' of undefined while using "useRef"

i am trying to use useRef in my react functional component, but when i try to access it I am getting error
"TypeError: Cannot read property 'onMonthSelect' of undefined while using "useRef" " .
Here is the code below for this
import React, { useRef, useState, useEffect } from "react";
import moment from "moment";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import { SingleDatePicker } from "react-dates";
const SingleDatePickerComponent = () => {
const monthController = useRef();
const [createdAt, setCreatedAt] = useState(moment());
const onDateChange = (createdAt) => {
console.log(createdAt);
setCreatedAt(createdAt);
};
useEffect(() => {
console.log(monthController);
// TODO: check if month is visible before moving
monthController.current.onMonthSelect(
monthController.current.month,
createdAt.format("M")
);
//In this useEffect i am getting the error
}, [createdAt]);
return (
<div>
<div style={{ marginLeft: "200px" }}>
</div>
<SingleDatePicker
date={createdAt}
startDateId="MyDatePicker"
onDateChange={onDateChange}
renderMonthElement={(...args) => {
// console.log(args)
monthController.current = {
month: args[0].month,
onMonthSelect: args[0].onMonthSelect,
};
// console.log(monthController)
return args[0].month.format("MMMM");
}}
id="SDP"
/>
</div>
);
};
export default SingleDatePickerComponent;
The ref value won't be set yet on the initial render. Use a guard clause or Optional Chaining operator on the access.
useEffect(() => {
// TODO: check if month is visible before moving
monthController.current && monthController.current.onMonthSelect(
monthController.current.month,
createdAt.format("M")
);
}, [createdAt]);
or
useEffect(() => {
// TODO: check if month is visible before moving
monthController.current?.onMonthSelect(
monthController.current.month,
createdAt.format("M")
);
}, [createdAt]);
It may also help to provide a defined initial ref value.
const monthController = useRef({
onMonthSelect: () => {},
});

SingleDatePicker by react-dates is not closing on change

Hey I have set up a react dates functionality on my app, however the date, when chosen doesnt make the calendar close.
I have the example here on https://codesandbox.io/s/magical-dubinsky-xuxkj?file=/src/App.js:0-681
import React, { useState } from "react";
import { SingleDatePicker } from "react-dates";
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
const CreateGroupEvent = (props) => {
const [dob, setDob] = useState(null);
const [focused, setFocused] = useState(false);
const setDate = (date) => {
setDob(date);
setFocused(false);
};
return (
<>
<SingleDatePicker
date={dob}
// {...input}
onOutsideClick={true}
numberOfMonths={1}
onDateChange={setDate}
focused={focused}
onFocusChange={setFocused}
id="dob"
/>
</>
);
};
export default CreateGroupEvent;
** EDITED : Here is my example code sandbox.
How about trying this?
According to its document, onFocusChange seems to should take { focused : boolean } objects as parameters.
const onFocusChange = ({ focused }) => {
setFocused(focused);
};
<SingleDatePicker
date={dob}
onOutsideClick={true}
numberOfMonths={1}
onDateChange={setDate}
focused={focused}
onFocusChange={onFocusChange}
id="dob"
/>
This seems to be a version related quirk -- if you just do:
onFocusChange={(focusedInput)=> setFocused(focusedInput.focus)}
it'll work.

lodash debounce in React functional component not working

I have a functional component built around the React Table component that uses the Apollo GraphQL client for server-side pagination and searching. I am trying to implement debouncing for the searching so that only one query is executed against the server once the user stops typing with that value. I have tried the lodash debounce and awesome debounce promise solutions but still a query gets executed against the server for every character typed in the search field.
Here is my component (with irrelevant info redacted):
import React, {useEffect, useState} from 'react';
import ReactTable from "react-table";
import _ from 'lodash';
import classnames from 'classnames';
import "react-table/react-table.css";
import PaginationComponent from "./PaginationComponent";
import LoadingComponent from "./LoadingComponent";
import {Button, Icon} from "../../elements";
import PropTypes from 'prop-types';
import Card from "../card/Card";
import './data-table.css';
import debounce from 'lodash/debounce';
function DataTable(props) {
const [searchText, setSearchText] = useState('');
const [showSearchBar, setShowSearchBar] = useState(false);
const handleFilterChange = (e) => {
let searchText = e.target.value;
setSearchText(searchText);
if (searchText) {
debounceLoadData({
columns: searchableColumns,
value: searchText
});
}
};
const loadData = (filter) => {
// grab one extra record to see if we need a 'next' button
const limit = pageSize + 1;
const offset = pageSize * page;
if (props.loadData) {
props.loadData({
variables: {
hideLoader: true,
opts: {
offset,
limit,
orderBy,
filter,
includeCnt: props.totalCnt > 0
}
},
updateQuery: (prev, {fetchMoreResult}) => {
if (!fetchMoreResult) return prev;
return Object.assign({}, prev, {
[props.propName]: [...fetchMoreResult[props.propName]]
});
}
}).catch(function (error) {
console.error(error);
})
}
};
const debounceLoadData = debounce((filter) => {
loadData(filter);
}, 1000);
return (
<div>
<Card style={{
border: props.noCardBorder ? 'none' : ''
}}>
{showSearchBar ? (
<span className="card-header-icon"><Icon className='magnify'/></span>
<input
autoFocus={true}
type="text"
className="form-control"
onChange={handleFilterChange}
value={searchText}
/>
<a href="javascript:void(0)"><Icon className='close' clickable
onClick={() => {
setShowSearchBar(false);
setSearchText('');
}}/></a>
) : (
<div>
{visibleData.length > 0 && (
<li className="icon-action"><a
href="javascript:void(0)"><Icon className='magnify' onClick= {() => {
setShowSearchBar(true);
setSearchText('');
}}/></a>
</li>
)}
</div>
)
)}
<Card.Body className='flush'>
<ReactTable
columns={columns}
data={visibleData}
/>
</Card.Body>
</Card>
</div>
);
}
export default DataTable
... and this is the outcome: link
debounceLoadData will be a new function for every render. You can use the useCallback hook to make sure that the same function is being persisted between renders and it will work as expected.
useCallback(debounce(loadData, 1000), []);
const { useState, useCallback } = React;
const { debounce } = _;
function App() {
const [filter, setFilter] = useState("");
const debounceLoadData = useCallback(debounce(console.log, 1000), []);
function handleFilterChange(event) {
const { value } = event.target;
setFilter(value);
debounceLoadData(value);
}
return <input value={filter} onChange={handleFilterChange} />;
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
To add onto Tholle's answer: if you want to make full use of hooks, you can use the useEffect hook to watch for changes in the filter and run the debouncedLoadData function when that happens:
const { useState, useCallback, useEffect } = React;
const { debounce } = _;
function App() {
const [filter, setFilter] = useState("");
const debounceLoadData = useCallback(debounce(fetchData, 1000), []);
useEffect(() => {
debounceLoadData(filter);
}, [filter]);
function fetchData(filter) {
console.log(filter);
}
return <input value={filter} onChange={event => setFilter(event.target.value)} />;
}
ReactDOM.render(<App />, document.getElementById("root"));
You must remember the debounced function between renders.
However, you should not use useCallback to remember a debounced (or throttled) function as suggested in other answers. useCallback is designed for inline functions!
Instead use useMemo to remember the debounced function between renders:
useMemo(() => debounce(loadData, 1000), []);
I hope this post will get you to the solution ,
You don't have to use external library for Debouncing you can create your own custom hook follow my steps
step(1):- Create the custom hook of Debouncing
import { useEffect ,useState} from 'react';
export const UseDebounce = (value,delay)=>{
const [debouncedValue,setDebouncedValue]= useState();
useEffect(()=>{
let timer = setTimeout(()=>setDebouncedValue(value),delay)
return ()=> clearTimeout(timer);
},[value])
return debouncedValue
}
step(2) :- Now create the file in which you want to add throttle
import React from 'react'
import { useEffect } from 'react';
import { useState } from 'react';
import {UseDebounce} from "./UseDebounce";
function Test() {
const [input, setInput] = useState("");
const debouncedValue = UseDebounce(input,1000);
const handleChange = (e)=>{
setInput(e.target.value)
}
useEffect(()=>{
UseDebounce&& console.log("UseDebounce",UseDebounce)
},[UseDebounce])
return (
<div>
<input type="text" onChange={handleChange} value={input}/>
{UseDebounce}
</div>
)
}
export default Test;
NOTE:- To test this file first create react app then embrace my files in it
Hope this solution worthwhile to you

Resources