I have Conditional Rendering component in reactJs. i use latest react version, and use MaterialUi in my application. this component use to show a span with a text and as soon as user click on it, it change to a input with a component of MaterialUi and user can change the field by this component
import React from 'react';
import EditIcon from '#material-ui/icons/Edit';
import TextField from '#material-ui/core/TextField';
import { grey400 } from 'material-ui/styles/colors';
class InlineEditInput extends React.Component {
constructor(props) {
super(props);
this.state = {
hover: false,
edit: false,
value: this.props.children
};
this.textInput = React.createRef();
}
handleClick = event => {
event.stopPropagation();
if (!this.state.edit) {
this.setState({ value: this.props.children });
this.setState({ edit: true, hover: false });
}
};
handleBlur = () => {
this.setState({ edit: false });
if (this.state.value.length > 0 && this.state.value !== this.props.children) this.props.onChange(this.state.value);
else this.setState({ value: this.props.children });
};
handleMouseEnter = () => this.setState({ hover: true });
handleMouseLeave = () => this.setState({ hover: false });
render() {
let { hover, edit, value } = this.state;
const originalValue = this.props.children;
const styles = {
label: { minHeight: '2em', marginTop: '10px' },
editIcon: { width: 20, height: 20, fill: grey400, marginLeft: 8 },
editIconHidden: { width: 20, height: 20, fill: 'none', marginLeft: 8 }
};
const setFocus = () => {
this.textInput.focus();
};
if (!edit)
return (
<div onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<span onClick={this.handleClick}>{originalValue}</span>
{hover ? <EditIcon style={styles.editIcon} /> : <EditIcon style={styles.editIconHidden} />}
</div>
);
else
return (
<TextField
id="EditField"
ref={input => {
this.textInput = input;
setFocus();
}}
value={value}
onClick={this.handleClick}
onBlur={this.handleBlur}
onChange={event => this.setState({ value:event.target.value })}
/>
);
}
}
export default InlineEditInput;
At first an span with value of originalvalue that comes get from its props of this component, is rendered and by click on this, edit state changed to ture and a TextField component of MaterialUi is rendered and I want to focus on this TextFieldAs soon as it is rendered.
For this purpose, I render a TextField and define its ref property that pass input to a function with name of setFocus and in this function I write focus method.
But when I click on span and re-render of component is occurred, i faced with the error that said :
this2.textInput.focus is not a function
how can i write this component?
Try using componentDidUpdate life cycle hook
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.state.edit)
this.textInput.focus();
}
The reason your method is not getting the input to be focused might be due to the fact that the DOM is not yet inserted when you are actually creating the ref. More like the textInput element is created but it's not appended to the DOM. Just a hunch, not 100% sure.
Related
class App extends Component {
constructor() {
super()
this.state = { //state is what decribes our app
robot: robot,
searchfield: ''
}
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value })
console.log(this.state.robot);
}
render() {
const filteredRobots = this.state.robot.filter( robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return(
<div className='tc'>
<h1>ROBOFRIENDS</h1>
<SearchBox searchChange={ this.onSearchChange } />
<CardList robot = { filteredRobots }/>
</div>
);
}
}
I'm trying to enlarge the font size of ROBOFRIENDS,I've tried to create another css file for editing h1 and also tried
<h1 className="style:{fontSize=3em}">ROBOFRIENDS</h1>
But they both don't work. However, when I tried to use the same method for changing the font color and background color, they work!
Looking for someone can help me out with this problem.
You can not add styles with className prop. you have two options:
adding a className to the element and styling that className in css.
or adding style property like this: style={{ fontSize: '3em' }}
I prefer the second one:
style={{ fontSize: '3em' }}
Because like this you can pass variables to this.
But my favorite way is to use styled-components.
https://styled-components.com/
Check this out, this is a very clean way to style in react.js and reuse the stylings.
There are multiple ways. I would recommend installing 'styled-components'.
I have included an example of how you could use it below:-
import styled from 'styled-components';
export const StyledHeading = styled.h1`
font-size: 3em;
`;
class App extends Component {
constructor() {
super()
this.state = {
robot: robot,
searchfield: ''
}
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value })
console.log(this.state.robot);
}
render() {
const filteredRobots = this.state.robot.filter( robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
})
return(
<div className='tc'>
<StyledHeading>ROBOFRIENDS</StyledHeading>
<SearchBox searchChange={ this.onSearchChange } />
<CardList robot = { filteredRobots }/>
</div>
);
}
}
I have the following React component which is working as desired. After reading about fully controlled components in this blog post I'm wondering if this code could be refactored to make it fully controlled, which could eliminate the use of getDerivedStateFromProps, if I understand correctly. Being more familiar with Vue Native than React Native I'm looking for some guidance on how to go about doing such a refactor.
import React, { Component } from "react";
import { Container, Content, Picker } from "native-base";
export default class DynamicPicker extends Component {
constructor(props) {
super(props);
this.state = {
selected: this.props.selected
}
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.selected !== prevState.selected) {
return ({ selected: nextProps.selected });
} else {
return null;
}
}
onValueChange(value) {
this.setState({
selected: value
});
this.props.onValueChange(value);
}
itemsList = () => {
return (this.props.items.map( (item, index) => {
return (<Picker.Item label={item} key={index} value={item} />)
}));
}
render() {
return (
<Container>
<Content>
<Picker
// note
mode="dropdown"
style={{ borderColor: 'gray', borderWidth: 1, height: 40, margin: 5 }}
selectedValue={this.state.selected}
onValueChange={this.onValueChange.bind(this)}
>
{ this.itemsList() }
</Picker>
</Content>
</Container>
);
}
}
From what I'm seeing you actually don't need any state here or the method onValueChange.
Why do you want to get a value from props just to set it on the state? Can't you just use the selected value received as props?
Also, can't you just use the method onValueChange received from props? I don't see any need to make another one in this component, because you're setting a new state, but you're going to change the state after that because you call this.props.onValueChange. When any prop changes the component will rerender, therefore getDerivedStateFromProps will be called and it will modify the state.
Long story short, this is how I see this component:
import React, { Component } from "react";
import { Container, Content, Picker } from "native-base";
export default class DynamicPicker extends Component {
itemsList = () =>
// Implicit return from the arrow function
this.props.items.map( (item, index) => {
return (<Picker.Item label={item} key={index} value={item} />)
});
}
render() {
return (
<Container>
<Content>
<Picker
// note
mode="dropdown"
style={{ borderColor: 'gray', borderWidth: 1, height: 40, margin: 5 }}
selectedValue={this.props.selected}
onValueChange={this.props.onValueChange}
>
{ this.itemsList() }
</Picker>
</Content>
</Container>
);
}
}
I use Two package
slate-react and emoji-mart
I want to when choose an Emoji , it puts on my editor.
import React from "react";
import { render } from "react-dom";
import { Editor } from "slate-react";
import { initialValue } from "./initialValue";
// Define our app...
class MyEditor extends React.Component {
// Set the initial value when the app is first constructed.
state = {
value: initialValue
};
// On change, update the app's React state with the new editor value.
onChange = ({ value }) => {
this.setState({ value });
};
onKeyDown = (event, change) => {
// This used to have stuff in it, but I moved it all to plugins.
};
clickMe=()=>{
this.setState({ value : this.state.value });
};
// Render the editor.
render() {
return (
<div>
<h1 onClick={this.clickMe}>Slate Editor Demo</h1>
<div style={{ border: "1px solid black", padding: "1em" }}>
<Editor
value={this.state.value}
onChange={this.onChange}
onKeyDown={this.onKeyDown}
renderNode={this.renderNode}
spellCheck={false}
/>
</div>
</div>
);
}
}
export default MyEditor;
import React,{useState} from 'react';
import 'emoji-mart/css/emoji-mart.css';
import { Picker } from 'emoji-mart';
function Emoji() {
const [emoji,setEmoji] = useState(null);
const addEmoji = (e) => {
setEmoji(e.native)
};
return <Picker onSelect={addEmoji} />
}
export default Emoji;
Try passing the editor ref to picker. Then in Emoji component in addEmoji method, try editorRef.current.InsertText(e.native). After hours of trying to solve this:
const YourTextEditor = props => {
const editor = createEditor();
const addEmoji = async emoji => {
await setTimeout(() => {
editor.focus();
}, 100);
editor.insertText(emoji.native);
};
return (
<>
<Editor
value={initialValue}
/>
<Emoji addEmoji={addEmoji} />
</>
);
};
const Emoji = props => {
return (<Picker onSelect={e => props.addEmoji(e)} />);
};
I'm using ReactJS (and nodejs, mongodb..) and I have projects with the delete option and I want to show a delete alert confirm window and I'm using SweetAlert for the first time. It shows the SweetAlert but doesn't let me choose the option, delete the project immediately. I'll show a gif so you can see what is happening.
Thank you!
My ProjectPage Component:
import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import moment from 'moment';
import SweetAlert from 'react-bootstrap-sweetalert'
import Tasks from '../../TaskList/Tasks/Tasks';
import './ProjectPage.css';
class ProjectPage extends Component {
constructor(props) {
super(props);
this.state = {
project: {},
alert: null
};
}
componentDidMount() {
const { match: { params } } = this.props;
fetch(`/dashboard/project/${params.id}`)
.then(response => {
return response.json()
}).then(project => {
this.setState({
project: project
})
})
}
deleteProject(e){
const getAlert = () => (
<SweetAlert
warning
showCancel
confirmBtnText="Yes!"
confirmBtnBsStyle="danger"
cancelBtnBsStyle="default"
title="Are you sure you want to delete this project?"
onConfirm={() => this.deleteFile()}
onCancel={() => this.onCancelDelete()}
>
You will not be able to recover this project!
</SweetAlert>
);
this.setState({
alert: getAlert()
});
e.preventDefault();
}
onCancelDelete(){
this.setState({
alert: null
});
}
render() {
const { match: { params } } = this.props;
const BackgroundImage = {
backgroundImage: `url(${this.state.project.imageURL})`,
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
backgroundPosition: 'center',
height: '350px',
opacity: '0.7'
}
return (
<div>
<header style={BackgroundImage}>
[...]
<form method='POST' action={`/dashboard/project/${params.id}/delete?_method=DELETE`}>
<button id='button__project-delete' style={{ boxShadow: 'none' }} className='button__options--project btn btn-outline-secondary'
type='submit' onClick={() => this.deleteProject()}>Delete</button> {this.state.alert}
</form>
</header>
[...]
</div>
);
}
}
export default ProjectPage;
GIF what's happening:
It looks your page refreshed on button click, because it is inside a form object. On button click, click event can not be accessible. So e.preventDefault() does not work.
You have to pass event object to deleteProject() method.
Change this line
<button id='button__project-delete' style={{ boxShadow: 'none' }} className='button__options--project btn btn-outline-secondary'
type='submit' onClick={() => this.deleteProject()}>Delete</button> {this.state.alert}
to
<button id='button__project-delete' style={{ boxShadow: 'none' }} className='button__options--project btn btn-outline-secondary'
type='submit' onClick={(e) => this.deleteProject(e)}>Delete</button> {this.state.alert}
this.setState({
alert: getAlert()
});
Please check after changing this to
this.setState({
alert: getAlert
});
I'm using the official Semantic UI React components to create a web application. I have a form on a search page, which contains an input field.
import React from 'react'
import {Form} from "semantic-ui-react";
import RadiusOfSearchInput from "./RadiusOfSearchInput";
const NearbyShopsSearchForm = (props) => {
const { onSubmit, size, action, onChange, value, style } = props
return (
<Form onSubmit={onSubmit}>
<RadiusOfSearchInput size={size}
action={action}
onChange={onChange}
value={value}
style={style} />
</Form>
)
}
export default NearbyShopsSearchForm
The component that uses the form is as shown below:
import React, { Component } from 'react'
import {Menu, Container, Segment} from 'semantic-ui-react'
import ShopCardList from "../components/ShopCardList";
import axios from 'axios';
import NearbyShopsSearchForm from "../components/NearbyShopsSearchForm";
class NearbyShopsPage extends Component {
constructor(props) {
super(props)
this.state = {
radius: '',
shops: []
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange = (e, { value } ) => {
this.setState({ radius: value })
}
handleSubmit = (e, data) => {
const { radius } = this.state
const url = `/api/shops/#33.846978,-6.775816,${radius}`
axios.get(url)
.then((response) => {
this.setState({ shops: response.data })
})
.catch((error) => {
console.log(error)
})
e.preventDefault()
}
render() {
const { radius } = this.state
return (
<Segment basic>
<Menu fixed='top' size='huge' borderless>
<Menu.Item>
<NearbyShopsSearchForm onSubmit={this.handleSubmit}
size='large'
action={{ color: 'teal', content: 'Search', size: 'small' }}
onChange={this.handleChange}
value={radius}
style={{ width: '17.5em' }} />
</Menu.Item>
</Menu>
<Container style={{ marginTop: '5.5em' }}>
<ShopCardList shops={this.state.shops}/>
</Container>
</Segment>
)
}
}
export default NearbyShopsPage
I want to validate the form so it won't submit values other than decimals, which are valid values to represent a distance. I didn't find validation support in the SUIR official documentation. I'm aware of the redux-form possibility, but i fail to implement it correctly. what's the recommended and simplest way to implement the data validation feature?