JSX in fuction donot update state - javascript

Can anyone give an answer?
Unable to update the state when I click getbtn -> placeRange pass jsx to setbtn ->then unable to update the State when Silde the Range.
import React, { useState } from "react";
export default function Stack() {
const [value, setvalue] = useState(0);
const [btn, setbtn] = useState(<></>);
function placeRange() {
const jsx = (
<>
<input
type="range"
onChange={(e) => {
setvalue(e.target.value);
}}
/>
<h1>{value}</h1>
</>
);
setbtn(jsx);
}
return (
<>
<button onClick={placeRange}>getrange</button>
{btn}
</>
);
}

This seems to be working for me.
Here's a working example at codesandbox
import { useState } from "react";
export default function App() {
const [value, setvalue] = useState(0);
const [btn, setbtn] = useState(<></>);
function placeBtn() {
const jsx = (
<>
<button
onClick={() => {
setvalue(1);
}}
>
Convert to 1
</button>
</>
);
setbtn(jsx);
}
return (
<>
<h1>{value}</h1>
<button onClick={placeBtn}>getbtn</button>
{btn}
</>
);
}

Not sure I fully understand what you are trying to achieve, this is not clear enough for me.
From your code it seems you are trying to set an input range in place when clicking the button, then, you want this range to update the number below it.
If this is the case I suggest the following solution:
import React, { useState } from "react";
export default function Stack() {
const [value, setvalue] = useState(0);
const [showRange, setShowRange] = useState(false);
function placeRange() {
setShowRange(!showRange);
}
return (
<>
<button onClick={placeRange}>getrange</button>
{showRange && (
<>
<input
type="range"
onChange={(e) => {
setvalue(e.target.value);
}}
/>
<h1>{value}</h1>
</>
)}
</>
);
}

Related

How do I store a function call within Context

What I would like to be able to do is to initialize my context with a state and a function that updates that state.
For example, say I have the following:
export default function MyComponent () {
const MyContext = React.createContext()
const [myState, setMyState] = useState('1')
const contextValue = {
currentValue: myState,
setCurrentValue: (newValue) => setMyState(newValue)
}
return (
<MyContext.Provider value={contextValue}>
<MyContext.Consumer>
{e => <div onClick={() => e.setCurrentValue('2')}> Click me to change the value </div>}
{e.currentValue}
</MyContext.Consumer>
</MyContext.Provider>
)
}
The {e.currentValue} correctly outputs '1' at first, but when I click the button, nothing changes.
What I would expect is that e.setCurrentValue('2') would call setMyState('2'), which would update the state hook. This would then change the value of myState, changing the value of currentValue, and making '2' display.
What am I doing wrong?
You would want to return a fragment from the context as one JSX root.
Check here - https://playcode.io/931263/
import React, { createContext, useState } from "react";
export function App(props) {
const MyContext = React.createContext();
const [myState, setMyState] = useState("1");
const contextValue = {
currentValue: myState,
setCurrentValue: newValue => setMyState(newValue)
};
return (
<MyContext.Provider value={contextValue}>
<MyContext.Consumer>
{e => (
<>
<div onClick={() => e.setCurrentValue("2")}>
Click me to change the value
</div>
{e.currentValue}
</>
)}
</MyContext.Consumer>
</MyContext.Provider>
);
}
You're using e.currentValue outside of MyContext.Consumer context which does not have e, so it's throwing an error that e is not defined from e.currentValue.
You can wrap them up together under <MyContext.Consumer>{e => {}}</MyContext.Consumer>
function MyComponent() {
const MyContext = React.createContext();
const [myState, setMyState] = React.useState("1");
const contextValue = {
currentValue: myState,
setCurrentValue: (newValue) => setMyState(newValue),
};
return (
<MyContext.Provider value={contextValue}>
<MyContext.Consumer>
{(e) => (
<div>
<div onClick={() => e.setCurrentValue("2")}>
Click me to change the value
</div>
<div>{e.currentValue}</div>
</div>
)}
</MyContext.Consumer>
</MyContext.Provider>
);
}
ReactDOM.render(<MyComponent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

how to change child component state in reactjs

I came across the following problem: I need to use another component's function inside a component:
header.js
export default function Header() {
const [showModalLogin ,setShowModalLogin] = useState(false);
return(
<>
<span>Hi, <Link onClick={() =>{ setShowModalLogin(true)}}>login</Link> </span>
{showModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
home.js
import Header from '../../components/header/header';
export default function Home() {
return (
<>
<Header />
<Link onClick={() =>{ setShowModalLogin(true)}}>open login</Link>
</>
}
How do I do in home.js to call the setShowModalLogin function that is in header.js ? I'm trying to use the context api too, but I still can't solve it.
You can just place useState in Header component and pass setShowModalLogin as props:
import Header from '../../components/header/header';
export default function Home() {
const [isShowModalLogin ,setShowModalLogin] = useState(false);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}
export default function Header({ isShowModalLogin, setShowModalLogin }) {
return(
<>
<span>Hi, <Link onClick={() => setShowModalLogin(true)}>login</Link> </span>
{isShowModalLogin ? <LoginModal setShowModalLogin={setShowModalLogin}/> : ''}
</>
);
}
Then you can do it in this way:
Create Context
Save useState inside
Use it everywhere you need
export const YourContext = createContext();
export const YourProvider = ({ children }) => {
const [isShowModalLogin, setShowModalLogin] = useState(false);
const value = {
isShowModalLogin,
setShowModalLogin
};
return <YourContext.Provider value={value}>{children}</YourContext.Provider>;
}
// App.js
const App = () => {
return (
<YourProvider>
<AppContent />
</YourProvider>
)
}
So now you can use it like here:
import Header from '../../components/header/header';
export default function Home() {
const { isShowModalLogin, setShowModalLogin } = useContext(YourContext);
return (
<>
<Header isShowModalLogin={isShowModalLogin} setShowModalLogin={setShowModalLogin} />
<Link onClick={() => setShowModalLogin(true)}>open login</Link>
</>
}

Share the useState between two adjacent components in React

I need help, is there any possible way to send the useEffect submittedInput from search.js to AllThemeContext.js to use it as value of Provider ? Both are in two separated files.
Please I asked this question and none has responded please help me.
I don't want to move the search to context i want them to stay in separated files.
/Search js/
/*Import*/
import React, { useState } from "react";
import "./Search.scss";
/*Component*/
const Search = () => {
const [input, setInput] = useState("");
const [submittedInput, setSubmittedInput] = useState("");
const onFormSubmit = (e) => {
e.preventDefault();
setInput("");
};
return (
<>
<div className="Search">
<form onSubmit={onFormSubmit} className="Search__form">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
type="text"
placeholder=" Title, companies, expertise, or benefits"
style={{ fontFamily: "Poppins, FontAwesome" }}
></input>
<button onClick={() => setSubmittedInput(input)}>Search</button>
</form>
</div>
</>
);
};
export default Search;
AllThemeContext:
import React, { createContext, useState } from "react";
export const AllContext = createContext();
const AllContextProvider = (props) => {
const [input, setInput] = useState();
const [numbs, setNumbs] = useState(1);
return (
<AllContext.Provider value={{ input, numbs }}>
{props.children}
</AllContext.Provider>
);
};
export default AllContextProvider;

Enable-Disable button with ReactJS

I am trying to enable or disable a button based on whether or not there is text in my input but cant seem to achieve it. When I manually set {true OR false} in the disabled property of Button function it works fine but I am really confused on how to set that dynamically based on the content of the input.
Any guidance is super welcome!
This is my app code
import { useState } from "react";
function Input (props){
const { onChange, value } = props
return (<input value={value} onChange={onChange} type="text" placeholder="Add a ToDo" maxLength="50"/>)
}
function Button (props) {
const {onChange, state, text} = props
return (<button disabled={false} onChange={onChange}>{text}</button>)
}
function App() {
const [text, setText] = useState("");
const [state, setSate] = useState(true);
const handleChange = (event) => {
if (!setText(event.target.value)) {
setSate(false);
} else {
setSate(true);
}
};
return (
<div className="App">
<div className="container">
<Input value={text} onChange={handleChange} />
<Button onChange={() => handleChange(state)} text="Add" />
<Button onChange={() => handleChange(state)} text="Clean" />
</div>
);
}
export default App;
Button element should change to:
function Button (props) {
const {disabled, onChange, state, text} = props
return (<button disabled={disabled} onChange={onChange}>{text}</button>)
}
Rendering of it should change to:
...
<Button disabled={!text} onChange={() => handleBtn()} text="Add" />
...
Sandbox: https://codesandbox.io/s/zen-hawking-qqzkw?file=/src/App.js
The idea is to send down disabled prop which would be true if the there is no text in the field.
ALSO, handleChange should look like this:
const handleChange = (event) => {
setText(event.target.value);
};
because the rest of your code in that function does not do anything.
Buttons should have their own handler functions .e.g. const handleBtn = () => {};
So you should pass the state value you are using to store whatever the users write in the input to the button so that the button knows when the input has text on it or not. And then your second state value can be used to store your todo list, so something like this
import { useState } from "react";
function Input({ handleChange, value }) {
return (
<input
value={value}
onChange={handleChange}
type="text"
placeholder="Add a Todo"
maxLength="50"
/>
);
}
function Button({ handleClick, text, disabled }) {
return (
<button disabled={disabled} onClick={handleClick}>
{text}
</button>
);
}
function App() {
const [value, setValue] = useState("");
const [todoList, setTodoList] = useState([]);
const handleChange = (event) => {
setValue(event.target.value);
};
const handleAdd = () => {
setTodoList([...todoList, value]);
handleClear();
};
const handleClear = () => {
setValue("");
};
return (
<div className="App">
<div className="container">
<Input value={value} handleChange={handleChange} />
<Button handleClick={handleAdd} disabled={!value} text="Add" />
<Button handleClick={handleClear} disabled={!value} text="Clear" />
</div>
</div>
);
}
export default App;

How to avoid unexpected rendering while using React Context?

I have two functional component under my provider,
SubApp1 and SubApp2 and here when I am increasing counter1 in SubApp1 the SubApp2 also is rendering, even when it is not need to be re-rendered.
And when I am increasing counter2 in SubApp2 the SubApp1 also is rendering.
I know this happens regally, but How can avoid this situation ?
App.js:
import React, {useContext, useState, memo} from "react";
import "./styles.css";
export const MainContext = React.createContext();
export const MainProvider = ({children})=> {
const [counter1, setCounter1] = useState(0);
const [counter2, setCounter2] = useState(0);
return (
<MainContext.Provider value={{
counter1, setCounter1,
counter2, setCounter2,
}}>
{children}
</MainContext.Provider>
);
}
export const SubApp1 = memo(()=> {
const {counter1, setCounter1} = useContext(MainContext);
console.log('Counter 1: ', counter1);
return (
<div className="App">
<button onClick={()=> {
setCounter1(counter1+1);
}}>
Increase Count 1
</button>
</div>
);
});
export const SubApp2 = memo(()=> {
const {counter2, setCounter2} = useContext(MainContext);
console.log('counter2: ', counter2);
return (
<div className="App">
<button onClick={()=> {
setCounter2(counter2+1);
}}>
Increase Count 2
</button>
</div>
);
});
export default function App ({navigation}){
console.log('App Is rendering...');
return (
<div className="App">
<button onClick={()=> {
navigation.navigate('SubApp1');
}}>
navigate to SubApp1
</button>
<button onClick={()=> {
navigation.navigate('SubApp2');
}}>
navigate to SubApp2
</button>
</div>
);
}
index.js:
import React from "react";
import ReactDOM from "react-dom";
import App, {MainProvider} from "./App";
const MainApp = ()=> (
<MainProvider>
<App />
</MainProvider>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<MainApp />, rootElement);
You should pass the counter to the SubApps as props. Then memo will take care that only the component with changing props will be rerendered.
Something like this:
export const Wrapper1 = ()=> {
const {counter1, setCounter1} = useContext(MainContext);
return (
<SubApp1 {...{counter1, setCounter1}} />
);
};
export const SubApp1 = memo(({counter1, setCounter1})=> {
console.log('Counter 1: ', counter1);
return (
<div className="App">
<button onClick={()=> {
setCounter1(counter1+1);
}}>
Increase Count 1
</button>
</div>
);
});
export const SubApp2 = memo(({counter2, setCounter2})=> {
console.log('counter2: ', counter2);
return (
<div className="App">
<button onClick={()=> {
setCounter2(counter2+1);
}}>
Increase Count 2
</button>
</div>
);
});
export default function App (){
const {counter2, setCounter2} = useContext(MainContext);
console.log('App Is rendering...');
return (
<div className="App">
<Wrapper1/>
<SubApp2 {...{counter2, setCounter2}} />
</div>
);
}
Codesandbox link is not right...
I follow the tip of Peter Ambruzs, but i have a problem if i pass counter1 as a param. The component keep rerendering.
But, if i pass just setCounter1 function, its works fine.
Below, my example using typescript.
const Campaigns = (): JSX.Element => {
const { setAlert } = useContext(AlertContext);
return <InnerCampaign {...{ setAlert }} />;
};
const InnerCampaign = memo(
({ setAlert }: any): JSX.Element => {...},)
export default Campaigns;

Categories

Resources