React Router - Doesn't Automatically Route on Form Submission - react-router

I'm trying to route my search field to this route:
App.js
class App extends Component {
render() {
return (
<div className="App">
<Header />
<Switch>
<Route exact path='/:q' component={SearchPage} /> //trying to route here
</Switch>
<Footer />
</div>
);
}
}
SearchField.js
import React from 'react'
import { withRouter } from 'react-router-dom'
class SearchField extends React.Component {
constructor(props) {
super(props)
this.state = {
query: ''
}
}
handleChange = event => {
const {name, value, type, checked} = event.target
type === "checkbox" ? this.setState({ [name]: checked }) : this.setState({ [name]: value })
}
handleSubmit = event => {
event.preventDefault()
this.props.history.push(`/${this.state.query}`) //my routing attempt using history.push
}
render() {
return (
<div>
<form className="form-inline my-2 my-lg-0" onSubmit={this.handleSubmit}>
<input
className="form-control mr-sm-2"
type="search"
name="query"
onChange={this.handleChange}
value={this.state.query}
placeholder="Search"
aria-label="Search"
/>
<button className="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
)
}
}
export default withRouter(SearchField)
So whenever I type the query onto the search field, it correctly displays it on the address bar like this:
but the front-end stays intact without changing the query (and no console errors either - completely clean). It's only when I refresh the page is my new query safe, for example, comes into play. However, I need it to auto-refresh whenever I fire the enter or press the Search button on my query without the need of manually refreshing the page to see my query results.
I've read this post quite diligently and I've tried all these steps, but I'm still unsuccessful with any approach that I've read.

Figured it out! I had to use the componentWillReceiveProps life cycle function from React.
Code:
componentWillReceiveProps(nextProps) {
if ( nextProps.match.params.q !== this.props.match.params.q ) {
fetch(`//derpibooru.org/search.json?q=${nextProps.match.params.q}`)
.then(res => res.json())
.then(data => this.setState({ images: data }))
}
}
More information can be found here.

Related

Passing a html value as a parameter in react

I need to pass a html value as a parameter for my function like so:
<input type ="text" placeholder="Smart Contract Bytecode" name="name" id ="scbytecode"className="nice-textbox"/>
<button id="button" onClick={parseAddress("document.getElementById('smartcontract').value)"}>Submit!</button>
but Im getting an error:
TypeError: Cannot read property 'value' of null
here is the Full code.
Added this to give a better impression of whats going on cause the fixes below don't seem to fix it all. Any help is welcomed.
class App extends Component {
parseAddress(_smartcontract){
var contractObj = new ethweb3.eth.Contract(ERC20ABI, document.getElementById('smartcontract').value);
contractObj.getPastEvents(
'Transfer' || 'allEvents',
{
fromBlock: 0,
toBlock: 'latest'
},
function(err,res){
console.log(err,res);
//examples to access the data returned
console.log(res.length);
document.getElementById("totalAddresses").innerHTML = res.length;
document.getElementById("sampleAddress").innerHTML = res[0].returnValues.from;
document.getElementById("sampleAmount").innerHTML = res[0].returnValues.value;
}
);
}
deploSC = async () => {
const accounts = await goweb3.eth.getAccounts();
//const code = ethweb3.eth.getCode(document.getElementById('smartcontract').value); Not working
console.log(code);
goweb3.eth.sendTransaction({
from: accounts[0],
data: document.getElementById('scbytecode').value
}, function(error, hash){
console.log(error,hash);
});
}
render() {
return (
<div className="App">
<header className="App-header">
<p>
Enter the smart contract address:
<input type="text" name="name" id="smartcontract" className="nice-textbox"/>
<input type ="text" placeholder="Sc bytecode" name="name" id ="scbytecode"className="nice-textbox"/>
<button id="button" onClick={this.parseAddress}>Submit!</button>
<button onClick={this.deploSC}> Deploy Sc</button>
</p>
<p id="totalAddresses">0</p>
<p id="sampleAddress">0</p>
<p id="sampleAmount">0</p>
</header>
</div>
);
}
}
export default App;
There is a better way to do this in React using state and not directly accessing the DOM which should be avoided.
Store the value of an input in the component's state, then give it to the button's onClick event handler via this.state.inputVal.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
inputVal: ''
};
}
inputChanged = (e) => {
this.setState({ inputVal: e.target.value });
}
render() {
return (
<div>
<input type ="text" placeholder="Smart Contract Bytecode" name="name" id ="scbytecode" className="nice-textbox" onChange={this.inputChanged}/>
<button id="button" onClick={() => { console.log(this.state.inputVal); }}>Submit!</button>
</div>
);
}
}
// Render it
ReactDOM.render(
<App/>,
document.getElementById("react")
);
<div id="react"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I think there is mismatch in id.
line 1 you gave "scbytecode"
line 2 you are trying access by id "smartcontract" which is not present, so you are seeing null

How to login validation using my api in React Js

React JS
I'm new to react js
In my api there is username and password. If the user login, have to validate from my json value
handleSubmit(e) {
fetch('https://randomuser.me/api?results=1')
.then((response) => {
return response.json()
.then((json) => {
if (response.ok) {
return Promise.resolve(json)
}
return Promise.reject(json)
})
})
alert(json) not working to check the result.
How can i fetch the username and password in the response?
And how to take this next page if the user was logged in successfully ?
My full Code
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup';
const ReactCSSTG = CSSTransitionGroup;
class App extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: true
}
// Bindings
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemount = this.handleRemount.bind(this);
}
handleSubmit(e) {
alert("dsa");
fetch('https://randomuser.me/api?results=1')
.then((response) => {
return response.json()
.then((json) => {
if (response.ok) {
return Promise.resolve(json)
}
return Promise.reject(json)
})
})
}
handleRemount(e) {
this.setState({
isVisible: true
}, function () {
console.log(this.state.isVisible)
});
e.preventDefault();
}
render() {
// const for React CSS transition declaration
let component = this.state.isVisible ? <Modal onSubmit={this.handleSubmit} key='modal' /> : <ModalBack onClick={this.handleRemount} key='bringitback' />;
return <ReactCSSTG transitionName="animation" transitionAppear={true} transitionAppearTimeout={500} transitionEnterTimeout={500} transitionLeaveTimeout={300}>
{component}
</ReactCSSTG>
}
}
// Modal
class Modal extends React.Component {
render() {
return <div className='Modal'>
<Logo />
<form onSubmit={this.props.onSubmit}>
<Input type='text' name='username' placeholder='username' />
<Input type='password' name='password' placeholder='password' />
<button> Sign In</button>
</form>
<a href='#'>Lost your password ?</a>
</div>
}
}
// Generic input field
class Input extends React.Component {
render() {
return <div className='Input'>
<input type={this.props.type} name={this.props.name} placeholder={this.props.placeholder} required />
<label htmlFor={this.props.name}></label>
</div>
}
}
// Fake logo
class Logo extends React.Component {
render() {
return <div className="logo">
<i><img src={logo} className="App-logo" alt="logo" /></i>
<span> Test </span>
</div>
}
}
// Button to brind the modal back
class ModalBack extends React.Component {
render() {
return (
<button className="bringitback" onClick={this.props.onClick} key={this.props.className}>Back to login page!</button>
);
}
}
export default App;
Thanks in Advance!
If you just want to catch data for now this will do the trick
fetch('https://randomuser.me/api?results=1')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
fetch('https://randomuser.me/api?results=1')
.then((response) => {
// check for status code from service if success
// set response in state such as login success
this.route.navigate(['/']);
})
.catch(error =>{
console.log(error);
});
})
Taking user to next page. Use react router for achieving this.
Step 1: Wrap your <App /> inside <BrowserRouter />
Now validate response if username/password are correct using service call.
Then this.route.navigate(['/']);
This will navigate user to home page of app after successful login.
Heres What I did, keep in mind I set up my backend with express/node.
I used Axios to fetch from my api.
onSubmit = (e) => {
e.preventDefault();
axios.get('API_PATH')
.then(res => {
const user = res.data[0].username;
const password = res.data[0].password;
const username = this.state.username;
const passwordEntered = this.state.password;
if(username === '' && passwordEntered === ''){
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
}else if(user === username && passwordEntered === password){
document.getElementById('status').innerHTML = '';
console.log(user, password)
}else{
document.getElementById('status').innerHTML = '<p>Please Enter A Valid Username and Password</p>';
}
})
.catch(error => {
console.log(error);
});
}
Here is the form I used.
<Form
>
<Form.Row>
<Form.Group as={Col}>
<Form.Label>Username</Form.Label>
<Form.Control
type="text"
name="username"
id="username"
value={this.state.value}
onChange={this.handleChange}
>
</Form.Control>
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Password</Form.Label>
<Form.Control
type="text"
id="password"
name="password"
value={this.state.value}
onChange={this.handleChange}
/>
</Form.Group>
</Form.Row>
<Button className="btn btn-sm btn-light" onClick={this.onSubmit}>
<i style={redColor} className="fas fa-sign-in-alt"></i> Login
</Button>
</Form>

Toggle between the visibility of 2 divs in reactjs

I have a simple reactjs website hosted on GitHub Pages. It lists articles, something like feeds in reddit. I have an AddArticle requirement, wherein, upon clicking the 'Add Article' button on the bottom of the page, the Div containing this button must become hidden, and a new Div for adding the details of the article(containing 2 text-boxes and a button named 'Submit') must show up. Upon clicking the 'Submit' button, the earlier Div has to reappear with the new Div getting hidden.
The following is the code I currently use(that is incomplete). Please go through it and provide any insight into the problem. Thanks.
class Child extends React.Component {
constructor(props) {
super(props);
this.onClickSubmitButton = this.onClickSubmitButton.bind(this);
this.state = {
showing: false
};
}
onClickSubmitButton(){
console.log('test-2');
this.setState(
{
showing: true
}
);
}
render() {
const { showing } = this.state;
return (
<div id="div_2">
<br/>
<input type="text" placeholder="Add the article title here" className="block_text"></input>
<br/><br/>
<input type="text" placeholder="Add the article text here" className="block_text"></input>
<br/><br/>
<button
type="button"
onClick={() =>
this.onClickSubmitButton()}
>
Submit
</button>
{ showing
? <div>This is visible</div>
: null
}
</div>
);
}
}
export default class AddArticle extends React.Component {
constructor(props) {
super(props);
this.onClickAddButton = this.onClickAddButton.bind(this);
this.state = {
error: undefined,
tempArticle: undefined,
childVisible: false,
parentVisible: true
};
}
onClickAddButton(){
console.log('test-1');
this.setState(
prevState => (
{
childVisible: !prevState.childVisible,
parentVisible: !prevState.parentVisible
}
)
);
}
// this is the render method
render() {
return (
<div id="div_1">
<br/><br/>
<button
type="button"
onClick={() =>
this.onClickAddButton()}
>
Add Article
</button>
{
this.state.childVisible
? <Child />
: null
}
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Here is a solution. You should had just send prop to the <Child /> component
DEMO

React: Auto update date and view with new information called from json API

I am calling data from coinmarketcap.com API and can not find a way to make the code auto update. I would like to get this code to update the information every 30 seconds or so.
If I call something the wrong thing... or this is a basic question, sorry this is my first week with React.
Here is what I have and it works great at loading the information from coinmarketcap.com on the when the app first loads.
Main Component (file: Crypto.jsx)
import React, { Component } from 'react';
import CryptoItem from './parts/CryptoItem';
class Crypto extends Component{
render(){
return(
<div id="CryptoItems">
<div id="data">
<CryptoItem cryptocoin="bitcoin" />
<CryptoItem cryptocoin="ethereum" />
<CryptoItem cryptocoin="ripple" />
<CryptoItem cryptocoin="iconomi" />
<CryptoItem cryptocoin="litecoin" />
<CryptoItem cryptocoin="bitcoin-cash" />
</div>
</div>
);
}
}
export default Crypto;
Child Component (file: /parts/CryptoItem.jsx)
import React, { Component } from 'react';
const urlForUsername = cryptocoin => `https://api.coinmarketcap.com/v1/ticker/${cryptocoin}/`
class CryptoItem extends Component {
constructor(props){
super(props)
this.state = {
requestFailed: false
}
}
componentDidMount(){
fetch(urlForUsername(this.props.cryptocoin))
.then(response =>{
if(!response.ok){
throw Error("Network request failed")
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cryptoData: d[0]
})
},() => {
this.setState({
requestFailed: true
})
})
}
render() {
if(this.state.requestFailed) return <p>Failed...</p>
if(!this.state.cryptoData) return <p>Loading...</p>
return(
<ul className="CryptoItem" data-sort={ `${this.state.cryptoData.percent_change_24h}` } id={ `${this.state.cryptoData.symbol}PriceChangeID` }>
<li>
{this.state.cryptoData.name}:
</li>
<li>
$ <span id={ `${this.state.cryptoData.symbol}Price` }>{this.state.cryptoData.price_usd}</span>
</li>
<li className="PreCentChange">
<span id={ `${this.state.cryptoData.symbol}PriceChange` }>{this.state.cryptoData.percent_change_24h}</span><b>%</b>
</li>
</ul>
);
}
}
export default CryptoItem;
First, extract out the logic in componentDidMount method in child component to a separate method as below.
fetchResult = () => {
fetch(urlForUsername(this.props.cryptocoin))
.then(response =>{
if(!response.ok){
throw Error("Network request failed")
}
return response
})
.then(d => d.json())
.then(d => {
this.setState({
cryptoData: d[0]
})
},() => {
this.setState({
requestFailed: true
})
})
}
After that modify the componentDidMount method as below.
componentDidMount(){
this.fetchResult()
setInterval(this.fetchResult, 30000)
}
Note that, setInterval method can be used to execute a logic periodically. The first argument is the function which contains the logic that needs to be executed periodically. Second argument is the time interval in milliseconds.

How to reset ReactJS file input

I have file upload input:
<input onChange={this.getFile} id="fileUpload" type="file" className="upload"/>
And I handle upload this way:
getFile(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = (theFile) => {
var data = {
blob: theFile.target.result, name: file.name,
visitorId: this.props.socketio.visitorId
};
console.log(this.props.socketio);
this.props.socketio.emit('file-upload', data);
};
reader.readAsDataURL(file);
}
If I upload same file twice, then upload event is not fired. How can I fix that? For simple js code it was enough to do the following: this.value = null; in change handler. How can I do it with ReactJS?
I think you can just clear the input value like this :
e.target.value = null;
File input cannot be controlled, there is no React specific way to do that.
Edit For old browsers (<IE11), you can use one of the following techniques.
See http://jsbin.com/zurudemuma/1/edit?js,output (tested on IE10 & 9)
What worked for me was setting a key attribute to the file input, then when I needed to reset it I update the key attribute value:
functionThatResetsTheFileInput() {
let randomString = Math.random().toString(36);
this.setState({
theInputKey: randomString
});
}
render() {
return(
<div>
<input type="file"
key={this.state.theInputKey || '' } />
<button onClick={this.functionThatResetsTheFileInput()} />
</div>
)
}
That forces React to render the input again from scratch.
This work for me - ref={ref => this.fileInput = ref}
<input id="file_input_file" type="file" onChange={(e) => this._handleFileChange(e)} ref={ref=> this.fileInput = ref} />
then in my case once the file was uploaded to the server , I clear it by using the statement below
this.fileInput.value = "";
I do it by updating key inside my file input.
This will force a re-render and previously selected file will go away.
<input type="file" key={this.state.inputKey} />
Changing the state inputKey will re-render the component.
One way to change the inputKey will be to always set it to Date.now() on click of a button which is supposed to clear the field.
With every click onClick you can reset the input, so that even with the same file onChange will be triggered.
<input onChange={this.onChange} onClick={e => (e.target.value = null)} type="file" />
import React, { useRef } from "react";
export default function App() {
const ref = useRef();
const reset = () => {
ref.current.value = "";
};
return (
<>
<input type="file" ref={ref} />
<button onClick={reset}>reset</button>
</>
);
}
The following worked for me using React Hooks. This is done using what is known as a "controlled input". That means, the inputs are controlled by state, or their source of truth is state.
TL;DR Resetting the file input was a two-step process using both the useState() and useRef() hooks.
NOTE: I also included how I reset a text input in case anyone else was curious.
function CreatePost({ user }) {
const [content, setContent] = React.useState("");
const [image, setImage] = React.useState(null); //See Supporting Documentation #1
const imageInputRef = React.useRef(); //See Supporting Documentation #2
function handleSubmit(event) {
event.preventDefault(); //Stop the pesky default reload function
setContent(""); //Resets the value of the first input - See #1
//////START of File Input Reset
imageInputRef.current.value = "";//Resets the file name of the file input - See #2
setImage(null); //Resets the value of the file input - See #1
//////END of File Input Reset
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Add Post Content"
onChange={event => setContent(event.target.value)}
value={content} //Make this input's value, controlled by state
/>
<input
type="file"
onChange={event => setImage(event.target.files[0])} //See Supporting Doc #3
ref={imageInputRef} //Apply the ref to the input, now it's controlled - See #2
/>
<button type="submit">Submit Form</button>
</form>
</div>
)
};
Supporting Documentation:
useState Hook
Returns a stateful value, and a function to update it.
useRef Hook
If you pass a ref object to React, React will set its current property to the corresponding DOM node whenever that node changes.
Using files from web apps
If the user selects just one file, it is then only necessary to consider the first file of the list.
You can also include this in your input element if you know you are not going to be using the built-in file input value at all.
<input value={""} ... />
This way the value is always reset to the empty string on render and you don't have to include it awkwardly in an onChange function.
I know file input is always uncontrolled however the following code still works in my own porject, I can reset the input with no problems at all.
constructor(props) {
super(props);
this.state = {
selectedFile: undefined,
selectedFileName: undefined,
imageSrc: undefined,
value: ''
};
this.handleChange = this.handleChange.bind(this);
this.removeImage = this.removeImage.bind(this);
}
handleChange(event) {
if (event.target.files[0]) {
this.setState({
selectedFile: event.target.files[0],
selectedFileName: event.target.files[0].name,
imageSrc: window.URL.createObjectURL(event.target.files[0]),
value: event.target.value,
});
}
}
// Call this function to reset input
removeImage() {
this.setState({
selectedFile: undefined,
selectedFileName: undefined,
imageSrc: undefined,
value: ''
})
}
render() {
return (
<input type="file" value={this.state.value} onChange={this.handleChange} />
);
}
We can reset file input by using key = {this.state.fileInputKey} and initialsing fileInputKey to Date.now() in constructor state.
On file upload success , we need to again assign fileInputKey: Date.now(), so it will have different value than previous and it create new file input component on next render()
We can also do this manually by clicking button to clear/reset file Input
Below is the working code :
import React from "react";
import { Button } from "reactstrap";
class FileUpload extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedFile: null,
fileInputKey: Date.now(),
message: ""
};
this.handleClear = this.handleClear.bind(this);
this.onClickHandler = this.onClickHandler.bind(this);
this.onChangeHandler = this.onChangeHandler.bind(this);
}
onChangeHandler = event => {
this.setState({
selectedFile: event.target.files
});
};
onClickHandler = () => {
if (this.state.selectedFile === null) {
this.setState({
message: "Please select File"
});
return;
}
//axios POST req code to send file to server
{
/**
const data = new FormData()
data = this.state.selectedFile[0]
axios.post("http://localhost:8080/api/uploadFile/", data)
.then(res => {
if (res.status == 200) {
// upload success
}
})
.catch(err => {
//message upload failed
})
*/
}
//after upload to server processed
this.setState({
selectedFile: null,
fileInputKey: Date.now(),
message: "File Uploaded"
});
};
handleClear() {
this.setState({
selectedFile: null,
fileInputKey: Date.now(),
message: ""
});
}
render() {
return (
<div>
<input
type="file"
key={this.state.fileInputKey}
class="form-control"
onChange={this.onChangeHandler}
/>
<button
type="button"
class="btn btn-success btn-block"
onClick={this.onClickHandler}
>
Upload
</button>
<Button
type="button"
value="Clear"
data-test="clear"
onClick={this.handleClear}
>
{" "}
Clear{" "}
</Button>
<br />
<label>{this.state.message}</label>
</div>
);
}
}
export default FileUpload;
Here is my solution using redux form
class FileInput extends React.Component {
constructor() {
super();
this.deleteImage = this.deleteImage.bind(this);
}
deleteImage() {
// Just setting input ref value to null did not work well with redux form
// At the same time just calling on change with nothing didn't do the trick
// just using onChange does the change in redux form but if you try selecting
// the same image again it doesn't show in the preview cause the onChange of the
// input is not called since for the input the value is not changing
// but for redux form would be.
this.fileInput.value = null;
this.props.input.onChange();
}
render() {
const { input: { onChange, value }, accept, disabled, error } = this.props;
const { edited } = this.state;
return (
<div className="file-input-expanded">
{/* ref and on change are key properties here */}
<input
className="hidden"
type="file"
onChange={e => onChange(e.target.files[0])}
multiple={false}
accept={accept}
capture
ref={(input) => { this.fileInput = input; }}
disabled={disabled}
/>
{!value ?
{/* Add button */}
<Button
className="btn-link action"
type="button"
text="Add Image"
onPress={() => this.fileInput.click()}
disabled={disabled}
/>
:
<div className="file-input-container">
<div className="flex-row">
{/* Image preview */}
<img src={window.URL.createObjectURL(value)} alt="outbound MMS" />
<div className="flex-col mg-l-20">
{/* This button does de replacing */}
<Button
type="button"
className="btn-link mg-b-10"
text="Change Image"
onPress={() => this.fileInput.click()}
disabled={disabled}
/>
{/* This button is the one that does de deleting */}
<Button
type="button"
className="btn-link delete"
text="Delete Image"
onPress={this.deleteImage}
disabled={disabled}
/>
</div>
</div>
{error &&
<div className="error-message"> {error}</div>
}
</div>
}
</div>
);
}
}
FileInput.propTypes = {
input: object.isRequired,
accept: string,
disabled: bool,
error: string
};
FileInput.defaultProps = {
accept: '*',
};
export default FileInput;
In my case I had a functional component and after selecting a file it suppose to set the file name in the state so using any solution above was failing except the ref one which i fixed like this.
const fileUpload = props => {
const inputEl = useRef(null)
const onUpload = useCallback(e => {
uploadFile(fileDetails)
.then(res => {
inputEl.current.value = ''
})
.catch(err => {
inputEl.current.value = ''
})
})
return (
<input type='file' ref={inputEl} onChange={handleChange} />
<Button onClick={onUpload}>Upload</Button>
)
}
I recently got stumbled into this issue to reset the File type input field. I think it is still a milestone for most developers. So I thought I should share my solution.
Since we are listening to the onChange event to update the image file into some of our states, we will have our component rerendered once we set the state. In such case, we can specify the value of the input file as empty like value='' which will cause the input field to reset its value after each change of its value.
<input
type="file"
value=''
onChange={onChangeFnc}
/>