I have a react component that takes the input from a materialUi text form and uses a useState hook to update. On submit I want it to update another variable to the value. This is being used in an h1 element. However, the h1 element is not updating. I know the variable is updating because I log it in the console and it updates.
import React, { useState } from 'react';
import CssBaseline from '#mui/material/CssBaseline';
import { ThemeProvider, createTheme } from '#mui/material/styles';
import Alert from '#mui/material/Alert';
import { TextField } from '#mui/material';
import Button from '#mui/material/Button';
import './style.css';
import { useEffect } from 'react';
const darkTheme = createTheme({
palette: {
mode: 'dark',
},
});
export default function App() {
const [myValue, setValue] = useState('') // The original hook
let headingText = 'Hello World'
let onSubmit = (e) => {
e.preventDefault();
headingText = myValue;
console.log(headingText);
console.log(myValue);
};
return (
<>
<title>Text Changer</title>
<div className='joe'>
<ThemeProvider theme={darkTheme}>
<React.Fragment>
<CssBaseline />
<Alert severity="success">Page Loaded</Alert>
<h1>{headingText}</h1> // the h1 I want to update
<form onSubmit={onSubmit}>
<TextField id="outlined-basic" label="Search Text" variant="outlined" value={myValue} onChange={(e) => setValue(e.target.value)}/>
<br />
<br />
<Button variant="contained" color="primary" type="submit">Submit</Button>
</form>
</React.Fragment>
</ThemeProvider>
</div>
</>
);
}
You'll want to useState for that as well
const [headingText, setHeadingText] = useState('Hello World');
// ...
setHeadingText(myValue);
You have to create a state as
const [headingText, setHeadingText] = useState("Hello World");
CODESANDBOX DEMO.
and then onClick of a button you have to update state. React will re-render the component if the state changes
let onSubmit = (e) => {
e.preventDefault();
setHeadingText(myValue);
};
Related
Ive downloaded a DarkModeToggle npm for my react app however I am a bit confused as to actually add the functionallity. Currently the button lets me click it on the appbar and the button itself changes however the state of my app does not.
import React, { useState, useEffect } from "react";
import { Container, AppBar, Typography, Grow, Grid } from "#material-ui/core";
import { useDispatch } from "react-redux";
import DarkModeToggle from "react-dark-mode-toggle";
// import { getPosts } from './actions/posts'
import Posts from "./components/Posts/Posts";
import Form from "./components/Form/Form";
import wisp_logo from "./images/wisp_logo.png";
import useStyles from "./styles";
const App = () => {
const [currentId, setCurrentId] = useState();
const classes = useStyles();
const dispatch = useDispatch();
const [isDarkMode, setIsDarkMode] = useState(() => false);
return (
<Container maxwidth="lg">
<AppBar className={classes.appBar} position="static" color="inherit">
<DarkModeToggle
onChange={setIsDarkMode}
checked={isDarkMode}
size={80}
/>
</AppBar>
</Container>
);
};
export default App;
If you wish to customize the theme, you need to use the ThemeProvider component in order to inject a theme into your application. Here's a simple example:
Custom variables:
const darkTheme = createTheme({
palette: {
type: "dark"
}
});
Use the ThemeProvider component:
<ThemeProvider theme={darkTheme}>
<AppBar
position="static"
color={`${isDarkMode ? "default" : "primary"}`}
>
<DarkModeToggle
onChange={setIsDarkMode}
checked={isDarkMode}
size={80}
/>
</AppBar>
</ThemeProvider>
Using a ternary to change the theme:
color={`${isDarkMode ? "default" : "primary"}`}
Exemplo completo aqui: https://codesandbox.io/s/holy-wood-cdgpks?file=/src/App.js
I believe there are 2 things to change:
The first one is that "isDarkMode" is a boolean, and inside the useState you're using a function, so must be like this:
const [isDarkMode, setIsDarkMode] = useState(false);
Also, when sending the "setIsDarkMode" function you need to update your state, like this:
<DarkModeToggle
onChange={() => setIsDarkMode(prevState => !prevState)}
checked={isDarkMode}
size={80}
/>
So "onChange" is now a function that is going to update the state on every click
I am very new to React and was trying to make a context in React so that in my notes app such that I can trigger my custom made alert for relevant user activity but when I am trying to use the values from the context using useContext I am getting error : "Cannot destructure property 'alert' of 'Object(...)(...)' as it is undefined."
Here's the code:-
Creating Context
import React from 'react';
const AlertContext = React.createContext(null);
export default AlertContext;
Populating Value to the Context
import React,{useState} from 'react';
import AlertContext from "./AlertContext";
const ShowAlert = (props)=>{
const [alert,setAlert] = useState(null);
const showAlert = (message,type)=>{
setAlert({
msg:message,
type:type
})
setTimeout(()=>{
setAlert(null);
},3000);
}
return(
<AlertContext.Provider value={{alert,showAlert}}>
{props.children}
</AlertContext.Provider>
)
}
export default ShowAlert;
Trying to use the values
import React, { useContext } from "react";
import { Navbar, Button, Nav } from "react-bootstrap";
import { Link, useHistory } from "react-router-dom";
import ShowAlert from "../contexts/ShowAlert";
import MyAlert from "./MyAlert";
function Header() {
const {alert} = useContext(ShowAlert);
let history = useHistory();
const handleLogout = () => {
localStorage.removeItem("token");
history.push("/login");
};
return (
<>
<header>
<Navbar collapseOnSelect expand="lg" className="header">
<Navbar.Brand className="heading">
<Link to="/" className="headerLink">
Note Cloud
</Link>
<i className="fas fa-cloud-upload-alt cloudIcon"></i>
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="me-auto"></Nav>
{localStorage.getItem("token") && (
<Nav>
<Nav.Link>
<Button variant="primary" size="lg" onClick={handleLogout}>
Logout
</Button>
</Nav.Link>
</Nav>
)}
</Navbar.Collapse>
</Navbar>
</header>
<MyAlert alert={alert}></MyAlert>
</>
);
}
export default Header;
Edit:- MyAlert Component
import React, { useContext } from "react";
import { Alert } from "react-bootstrap";
import ShowAlert from "../contexts/ShowAlert";
const MyAlert = (props) => {
const {alert} = useContext(ShowAlert);
const capitalize = (word) => {
if(word==="danger")
{
word = "error";
}
const lower = word.toLowerCase();
return lower.charAt(0).toUpperCase() + lower.slice(1);
};
return (
<div style={{ height: "50px" , width:"100%"}}>
{alert && (
<Alert
variant={alert.type}
>
<Alert.Heading>{capitalize(alert.type)}</Alert.Heading>
<p>{capitalize(alert.msg)}</p>
</Alert>
)}
</div>
);
};
export default MyAlert;
Error That I am getting
Try doing the Context like this instead of null.
import React from "react";
const AlertContext = React.createContext({
alert: {},
setAlert: (alert) => {},
});
export default
i think your export is the fail
export const AlertContext = React.createContext({})
or as well you can try:
< AlertContext.Consumer>
{(context) => {
console.log(context)
}}
</AlertContext.Consumer>
I am getting the above error when passing the text input from one screen to another. Interestingly error is there when the app is launched and it is crashing the app. However, if I delete the line in the below code : const { input } = route.params; run the app. It will not crash. So, I can navigate to the screen with text input. Put some text in. And then add back the line const { input } = route.params; the app works, and data is passing from screen to screen. If I refresh the app, it crashes. I tried to hard code some data, so the Textinput is not empty when the app is launching. It did not work, app is still crashing on launch. Below is my code? Any ideas why mentioned behaviour is occurring?
Here I am navigating on Screen : Opci Podaci where the text input is located and also displaying data {input}:
import React, {useContext, useState} from "react";
import styled from "styled-components";
import { Text, View, ScrollView} from "react-native";
import {List} from "react-native-paper";
import { OpciPodaciOglasInput } from "../../components/iznajmljivanje.PodaciInput/opciPodaciInput";
export const IznajmiScreen = ({navigation, route}) => {
const { input } = route.params;
return (
<>
<SectionContainer>
<ScrollView>
<List.Accordion
title="Detalji Oglasa"
left={(props) => <List.Icon {...props} icon="car-sports" />}
expanded={detaljiExpanded}
onPress={() => setDetaljiExpanded(!detaljiExpanded)}
>
<List.Item title="Unesi Opis..."
onPress={()=>navigation.navigate("Opci Podaci")} />
<List.Item />
</List.Accordion>
<Text>{input}</Text>
</ScrollView>
</SectionContainer>
</>
);
};
Text input screen(Opci podaci in the code):
import React, {useState} from "react";
import styled from "styled-components";
import {TextInput, View, StyleSheet, Text, Button} from "react-native";
export const OpciPodaciOglasInput = ({navigation}) => {
const [input, setInput] = useState("");
return(
<>
<Button title="Save"
onPress={()=>navigation.navigate("Rent a car", {input})}/>
<InputContainer>
<Text>Unesi Podatke</Text>
<TextInput style={styles.input}
placeholder="300 rijeci maximum"
multiline = {true}
maxLength={300}
onChangeText={(text)=> setInput(text)}
returnKeyType='done'
value={input}
onSubmitEditing={()=>{
navigation.navigate('Rent a car',{input});
setInput("");
}}
/>
</InputContainer>
</>
);
};
And my navigation:
import React from "react";
import { Button } from "react-native";
import {createStackNavigator, CardStyleInterpolators} from "#react-navigation/stack";
import { IznajmiScreen } from "../screens/tabNavigation.screens/iznajmiScreen";
import { OpciPodaciOglasInput } from "../components/iznajmljivanje.PodaciInput/opciPodaciInput";
const IznajmiStack = createStackNavigator();
export const IznajmiScreenNavigator = ({ route, navigation }) => {
return (
<IznajmiStack.Navigator
screenOptions="screen"
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}
>
<IznajmiStack.Screen
options={{headerRight:()=>(<Button title="Predaj Oglas"
onPress={()=>{}}/>)}} //TODO on PRESS
name="Rent a car"
component={IznajmiScreen}
/>
<IznajmiStack.Screen name="Opci Podaci" component={OpciPodaciOglasInput}/>
</IznajmiStack.Navigator>
);
};
The issue is the line const { input } = route.params; - before react-navigation populates the route object, you will get an error trying to reference its nested properties. Safely accessing the route object will prevent this, i.e.
const { input } = route?.params || {};
As the title says my navbar is not changing the fragments after updating the state. I have no idea how to refresh it and other ideas seems to not work for me. I have tried to change the statements.
All i want to do is, after a user logs in successfully the state changes to true and the navbar updates with the corrent components. Thank you !
Home.js
import React, { useEffect } from 'react'
function Home() {
useEffect(()=>{
if(!localStorage.getItem("loggedIn")){
localStorage.setItem("loggedIn",false);
}
},[]);
return (
<div>
Home
</div>
)
}
export default Home
Login.js
import React from 'react';
import './Login.css';
import Axios from 'axios';
import { useEffect, useState } from "react";
import {useHistory} from 'react-router-dom';
function Login() {
const[username,setUsername] = useState('');
const[password,setPassword] = useState('');
const[errorMessage,setErrorMessage] = useState('');
let history = useHistory();
const login = () =>{
console.log(username);
Axios.post("http://localhost:3001/user/login",{username: username,password: password}).then((response) => {
//console.log(response);
if(response.data.loggedIn){
localStorage.setItem("loggedIn",true);
localStorage.setItem("username",response.data.username);
history.push('/');
}else{
setErrorMessage(response.data.message);
}
});
};
return (
<div className="Login">
<h1>Login to your BugTrack account !</h1>
<div className="LoginForm">
<input type="text" placeholder="USERNAME"
onChange={(event)=>{setUsername(event.target.value)}}/>
<input type="password" placeholder="PASSWORD"
onChange={(event)=>{setPassword(event.target.value)}}/>
<button onClick={login}>Login to you account</button>
<h1 style={{color: "red"}}>{errorMessage}</h1>
</div>
</div>
);
}
export default Login
Navbar.js
import React, { useEffect, useState, Component, Fragment } from 'react';
import './Navbar.css';
function Navbar() {
const [loggedIn, setLoggedIn] = useState(false);
useEffect(()=> {
setLoggedIn(localStorage.getItem("loggedIn"));
},[localStorage.getItem("loggedIn")]);
return (
<div className="Navbar">
Home
{!loggedIn ? (
<Fragment>
Profile
</Fragment>
):(
<Fragment>
Register
Login
</Fragment>
)}
</div>
);
}
export default Navbar;
You want to to use localStorage as a useEffect dependency which isn't supports for React to rerender/update the component. Check this: useEffect do not listen for localStorage - it's like duplicate of your question.
I'd like to supply a material UI TextField component to the PhoneInput component from react-phone-number-input as the inputComponent prop.
However, I don't seem to be able to successfully apply the ref. Although I see the Material UI TextField component rendered to the UI and state is successfully updated with the value, it keeps loosing focus after the first value has been typed.
import React, { forwardRef, createRef } from 'react';
import { TextField } from '#material-ui/core';
import 'react-phone-number-input/style.css';
import PhoneInput from 'react-phone-number-input';
const SampleComponent = ({ handleChange }) => {
const phoneInput = forwardRef((props, ref) => {
return (
<TextField
inputRef={ref}
fullWidth
label="Phone Number"
variant="outlined"
name="phone"
onChange={handleChange}
/>
);
});
const ref = createRef();
return (
<PhoneInput ref={ref} inputComponent={phoneInput} />
);
};
So I was able to get it to work using the following method. Any suggestions on how to improve this are more than welcome.
I have a separate file called PhoneNumber.jsx
import { forwardRef } from 'react'
import TextField from '#material-ui/core/TextField'
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles(theme => ({
input: {
backgroundColor: '#fff'
}
}))
const phoneInput = (props, ref) => {
const classes = useStyles()
return (
<TextField
{...props}
InputProps={{
className: classes.input
}}
inputRef={ref}
fullWidth
size='small'
label='Phone Number'
variant='outlined'
name='phone'
/>
)
}
export default forwardRef(phoneInput)
And my form file:
import PhoneInput from 'react-phone-number-input'
import CustomPhoneNumber from '../components/prebuilt/PhoneNumber'
...
<PhoneInput
placeholder='Enter phone number'
value={phone}
onChange={setPhone}
inputComponent={CustomPhoneNumber}
/>
...
There is also a package for Material UI v5 (or MUI) called Mui tel input and it's working with React 17 and 18 !
Simply way to use. Phone validation available too.
Check the doc here : https://github.com/viclafouch/mui-tel-input
import React from 'react'
import { MuiTelInput } from 'mui-tel-input'
const MyComponent = () => {
const [value, setValue] = React.useState('')
const handleChange = (newValue) => {
setValue(newValue)
}
return <MuiTelInput label="Phone" fullWidth value={value} onChange={handleChange} />
}