React setState inside solidity contract instance promises - javascript

I deployed a solidity contract to my local testrpc blockchain. All my contract method tests check out, but handling Web3 transactions and updating state accordingly is giving me trouble.
When I add a user account, my next operation is to return all user accounts for my contract. and well...update my state (RegisteredAccounts).
However, through my chain of promises I'm not seeing my states update. I understand setState is asynchronous too, so how can I see my states update without refreshing the page or calling ComponentDidMount()?
Here is my Solidity Accounts Contract (the parts that I've handled so far
pragma solidity ^ 0.4.4;
contract Accounts {
mapping(address => User) public mUsers;
address[] public Users; //users whitepages
struct User {
string handle;
bytes32[] taskList;
}
function addNewUser(string _handle) returns(bool success) {
address newUserAddr = msg.sender;
//if handle not in userAddresses & the handle is not null
if (bytes(mUsers[newUserAddr].handle).length == 0 && bytes(_handle).length != 0) {
mUsers[newUserAddr].handle = _handle;
Users.push(newUserAddr);
return true;
} else {
return false;
}
}
function getUsers() constant returns(address[]) {
return Users;
}
}
Here is my App container component -- relevant parts
registerNewUser() is my problem child right now.
class App extends Component {
state = {
modalOpen: false,
SenderAddress: null,
RegisteredAccounts: [],
isRegisteredUser: false,
SenderTaskList: [], //not set
AccountsCtrct: null,
web3: null
}
//#region APP METHODS
componentWillMount() {
// Get network provider and web3 instance. -- See utils/getWeb3 for more info.
getWeb3.then(results => {
this.setState({
web3: results.web3
})
this.instantiateContracts() //instantiate contract
}).catch(() => {
console.log('Error finding web3.')
})
}
instantiateContracts() {
this.setState({
AccountsCtrct: contract(AccountsContract)
})
this.state.AccountsCtrct.setProvider(this.state.web3.currentProvider)
//Get block chain addresses --- only returns the current address selected in metamask (web3 current addr)
this.state.web3.eth.getAccounts((error, accounts) => {
this.setState({
SenderAddress: accounts[0]
})
//INIT ACCOUNTS CONTRACT
var acctDeployed = this.state.AccountsCtrct.deployed()
acctDeployed.then((instance) => {
return instance.getUsers();
}).then((res) => {
this.setState({
RegisteredAccounts: res
})
if (this.state.RegisteredAccounts.includes(this.state.SenderAddress)) {
this.setState({
isRegisteredUser: true
})
}
})
})
}
registerUser = (handle) => {
var acctInstance
this.state.AccountsCtrct.deployed().then((inst) => {
//add current user to this account
acctInstance = inst
return acctInstance.addNewUser(handle, {
from: this.state.SenderAddress
});
}).then(() => {
//now we added our user -- update registeredAccounts setState
//pass response users array to promise
return acctInstance.getUsers()
}).then(res => {
this.setState({
RegisteredAccounts: res
})
if (res.includes(this.state.SenderAddress)) {
this.setState({
isRegisteredUser: true
})
}
})
}
toggleModal = () => {
this.setState(prevState => ({
modalOpen: !prevState.modalOpen
}));
}
//#endregion
render() {
return (
<div className="App">
<nav className="navbar pure-menu pure-menu-horizontal">
Truffle Box
{
!this.state.isRegisteredUser
? <a style={navLink} onClick={ this.toggleModal } href="#" className="pure-menu-heading pure-menu-link">Register</a>
: null
}
</nav>
<ModalUserNav visible={this.state.modalOpen}
toggleModal={this.toggleModal}
isRegistered={this.state.isRegisteredUser}
registerUser={this.registerUser} />
);
}
}
Last my Child component
class ModalUserNav extends Component {
state = {
unpl: "UserName",
pwpl: "Password",
errorCode: 'Registration Failed',
errorVisible: false
}
handleOnChangePL = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
handleSubmit = () => {
if (this.state.unpl !== "") {
this.props.registerUser(this.state.unpl)
this.props.toggleModal();
} else {
//if the input is empty update the error code and show
console.log('registration failed!')
this.setState({
errorCode: 'REGISTRATION ERR: empty handles are not allowed!',
errorVisible: true
})
}
}
render() {
return (
<section>
<Modal visible={this.props.visible} effect="fadeInUp">
<div className="pure-form">
<fieldset style={modalFormView}>
<legend style={{fontSize: "18px"}}><b>Register now. All you need is a handle!</b></legend>
<div className="flexContainer">
<input style={{marginTop: "7px", height: "2.6em", marginLeft: "5px", marginRight: "5px"}} type="text" name="unpl" placeholder={this.state.unpl} onChange={(event) => {this.handleOnChangePL(event)}} value={this.state.unpl} />
<button style={btnStyle} type="submit" className="pure-button pure-button-primary" onClick={() => {this.handleSubmit()}}><b>Register</b></button>
</div>
</fieldset>
</div>
</Modal>
</section>
)
}
}
In short, I want to follow up my 2 asynchronous tasks (addNewUser, getUsers) with a setState so I can automatically change my UI without refreshing. So what am I doing wrong?

You should move instantiateContracts to setState because setState does not update data immediately. https://reactjs.org/docs/react-component.html#setstate
this.setState({
web3: results.web3
}, () => {
this.instantiateContracts() //instantiate contract
})
Update 1: About registerUser: It should be
this.setState({
RegisteredAccounts: res
}, () => {
if (res.includes(this.state.SenderAddress)) {
this.setState({
isRegisteredUser: true
})
}
})

Related

Value returned of a form with Stripe CardElement is undefined React Axios

I'm new to this and try to create a dropdown list with my product names and use the key of this products (I have a Django Backend) to then proceed to payment with Stripe.
The problem is that the value of my product selected in my dropdown list (ie the variable named SelectedPlan) passed down here is 'undefined' ...but when I pass the value like a string 'string_value_of_my_Stripe_product' for example everything is fine and the payment and subscription work correctly.
The problem seems to be with the fact that the state is not updated correctly to the value in the form ie e.target.value does not update when I select the product in the userform
...this part :
Axios
.post("../myAPI/blablabla", {
SelectedPlan: this.SelectedPlan,
})
Here are the 2 files I have ... SubscribeForm.js and a Billing.js.
I'm sorry there's maybe too much code but it's maybe necessary to get thw whole idea...I try to not show the unnecessary...
Thanks in advance !!!
Here is my SubscribeForm.js
import React from "react";
import {
CardElement,
injectStripe,
Elements,
StripeProvider,
}
const subscriptionOptions = [
{...values here},
];
class StripeForm extends React.Component {
state = {
loading: false,
error: null,
SelectedPlan: null,
};
onSelectedPlanChange = e => {
this.setState({
SelectedPlan: e.target.value,
});
};
submit = (ev) => {
ev.preventDefault();
this.setState({ loading: true, error: null });
if (this.props.stripe) {
this.props.stripe.createToken().then((result) => {
if (result.error) {
this.setState({
error: result.error.message,
loading: false,
SelectedPlan: null,
});
} else {
Axios
.post(".../myAPI/blablabla/", {
SelectedPlan: this.SelectedPlan,
})
.then((res) => {
this.setState({
loading: false,
});
this.props.handleUserDetails();
})
.catch((err) => {
console.log(err);
this.setState({
loading: false,
error: err.response.data.message,
});
});
}
});
} else {
console.log("Stripe js hasn't loaded yet");
}
};
render() {
const { loading, error } = this.state;
return (
<React.Fragment>
<Divider />
{error && <Message error header="There was an error" content={error} />}
<Form onSubmit={this.submit}>
<Form.Select
options={subscriptionOptions}
placeholder="SelectedPlan"
onChange={this.onSelectedPlanChange}
name="SelectedPlan"
value={this.SelectedPlan}
/>
<CardElement />
<Button
loading={loading}
disabled={loading}
type='submit'
>
Confirm
</Button>
</Form>
</React.Fragment>
);
}
}
const WrappedStripeForm = injectStripe(StripeForm);
class SubscribeForm extends React.Component {
render() {
return (
<StripeProvider apiKey="my_test_key">
<div>
<Elements>
<WrappedStripeForm {...this.props} />
</Elements>
</div>
</StripeProvider>
);
}
}
export default SubscribeForm;
Here is my Billing.js :
import React from "react";
import SubscribeForm from "./SubscribeForm";
class Billing extends React.Component {
state = {
...
};
componentDidMount() {
this.handleUserDetails();
}
...some code
handleUserDetails = () => {
this.setState({
loading: true,
});
Axios
.get(".../myAPI/mybilling/")
.then((res) => {
this.setState({
loading: false,
billingDetails: res.data,
});
console.log("billing details ici");
console.log(res.data);
})
.catch((err) => {
this.setState({
loading: false,
error: err.response.data.message,
});
});
};
renderBillingDetails(details) {
return (
<Segment>
...some code
<SubscribeForm handleUserDetails={this.handleUserDetails} />
...some code
</Segment>
);
}
...some other code
}
export default Billing;

I got navigation as undefined in react navigation 5?

I have a reusable component for Sign in with Apple Button
After user success, i navigate hem to Home screen
But i notes when i log navigation it's log undefined,
and when i log this.props i just got the two actions i made in redux!
So how can i access to navigation in this component and why it's not accessed by default!
Log
props => {"isLogin": [Function isLogin], "storeToken": [Function storeToken]}
navigation => undefined
Code
import appleAuth, {
AppleAuthCredentialState,
AppleAuthError,
AppleAuthRealUserStatus,
AppleAuthRequestOperation,
AppleAuthRequestScope,
AppleButton,
} from '#invertase/react-native-apple-authentication';
import React from 'react';
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import {connect} from 'react-redux';
import API from '../../api/API';
import {isLoginFunc} from '../../redux/actions/isLoginAction';
import {saveToken} from '../../redux/actions/saveTokenAction';
class AppleAuth extends React.Component {
constructor(props) {
super(props);
this.authCredentialListener = null;
this.user = null;
this.state = {
credentialStateForUser: -1,
loading: false,
};
}
componentDidMount() {
const {navigation} = this.props;
console.log('did-navigation', navigation);
console.log('did- this.props', this.props);
/**
* subscribe to credential updates.This returns a function which can be used to remove the event listener
* when the component unmounts.
*/
this.authCredentialListener = appleAuth.onCredentialRevoked(async () => {
// console.warn('Credential Revoked');
this.fetchAndUpdateCredentialState().catch(error =>
this.setState({credentialStateForUser: `Error: ${error.code}`}),
);
});
this.fetchAndUpdateCredentialState()
.then(res => this.setState({credentialStateForUser: res}))
.catch(error =>
this.setState({credentialStateForUser: `Error: ${error.code}`}),
);
}
componentWillUnmount() {
/**
* cleans up event listener
*/
this.authCredentialListener();
}
signIn = async () => {
// start a login request
try {
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: AppleAuthRequestOperation.LOGIN,
requestedScopes: [
AppleAuthRequestScope.EMAIL,
AppleAuthRequestScope.FULL_NAME,
],
});
this.setState({loading: true});
const {
user: newUser,
email,
nonce,
fullName: {familyName, givenName},
identityToken,
realUserStatus /* etc */,
} = appleAuthRequestResponse;
let username = `${givenName} ${familyName}`;
this.user = newUser;
this.fetchAndUpdateCredentialState()
.then(res => {
this.setState({credentialStateForUser: res});
console.log('res:::', res);
})
.catch(error => {
console.log(`Error: ${error.code}`);
this.setState({credentialStateForUser: `Error: ${error.code}`});
});
if (identityToken) {
console.log('email', email);
console.log('username', username);
console.log('nonce', nonce);
this.sendData(email, username, nonce);
// e.g. sign in with Firebase Auth using `nonce` & `identityToken`
} else {
// no token - failed sign-in?
}
if (realUserStatus === AppleAuthRealUserStatus.LIKELY_REAL) {
console.log("I'm a real person!");
}
// console.warn(`Apple Authentication Completed, ${this.user}, ${email}`);
} catch (error) {
if (error.code === AppleAuthError.CANCELED) {
alert('User canceled Apple Sign in');
// console.warn('User canceled Apple Sign in.');
} else {
console.error(error);
}
}
};
fetchAndUpdateCredentialState = async () => {
if (this.user === null) {
this.setState({credentialStateForUser: 'N/A'});
} else {
const credentialState = await appleAuth.getCredentialStateForUser(
this.user,
);
if (credentialState === AppleAuthCredentialState.AUTHORIZED) {
this.setState({credentialStateForUser: 'AUTHORIZED'});
} else {
this.setState({credentialStateForUser: credentialState});
}
}
};
// Send data "name,image,email" to API
sendData = async (Email, Name, Id) => {
try {
let response = await API.post('/apple', {
email: Email,
name: Name,
id: Id,
});
let {
data: {
data: {
response: {token},
},
},
} = response;
console.log('token:?>:', token);
console.log('props', this.props);
console.log('navigation', this.props.navigation);
this.setState({loading: false});
this.props.storeToken(token);
this.props.isLogin(true);
// this.props.navigation.push('BottomTabNavigator');
} catch (err) {
console.log(err);
alert('Unexpected Error, try again later.');
this.setState({loading: false});
}
};
render() {
return (
<View style={styles.container}>
{this.state.loading ? (
<ActivityIndicator />
) : (
<AppleButton
style={styles.appleButton}
cornerRadius={5}
buttonStyle={AppleButton.Style.WHITE}
buttonType={AppleButton.Type.SIGN_IN}
onPress={() => this.signIn()}
/>
)}
</View>
);
}
}
const styles = StyleSheet.create({
appleButton: {
width: 200,
height: 50,
// margin: 10,
},
container: {
flex: 1,
justifyContent: 'center',
},
});
const mapDispatchToProps = dispatch => {
// to excute the actions we want to invok
return {
isLogin: isLogin => {
dispatch(isLoginFunc(isLogin));
},
storeToken: token => {
dispatch(saveToken(token));
},
};
};
export default connect(
null,
mapDispatchToProps,
)(AppleAuth);
-
singin.js
<AppleAuth /> in the render method
if you render your component as component, not as a navigation screen, it will not receive navigation prop. It was like this in all versions of react-navigation
Access the navigation prop from any component

Can't update state in React Context using function

I currently have two contexts - GalleryContext & AdminContext
In AdminContext, whenever I fire off handleSendImage(), I am trying to call a function (getGallery()) from GalleryContext which updates the gallery state in GalleryContext.
However, I am receiving this error:
Unhandled Rejection (TypeError): this.setState is not a function
Could anyone please advise me on how to fix this? Much appreciated in advance!
Here's my code:
GalleryContext:
class GalleryProvider extends Component {
state = {
gallery: []
};
getGallery() {
let database = firebase
.database()
.ref("/gallery/")
.once("value")
.then(images => {
console.log(images.val());
this.setState(
{
gallery: images.val()
},
() => {}
);
});
}
componentDidMount() {
this.getGallery();
}
render() {
return (
<GalleryContext.Provider
value={{
...this.state,
getGallery: this.getGallery
}}>
{this.props.children}
</GalleryContext.Provider>
);
}
}
AdminContext.js
class AdminProvider extends Component {
static contextType = GalleryContext;
state = {
upload_image: null,
gallery_title: null,
gallery_description: null,
gallery_filename: null,
progress: null
};
handleSendImage = (event, gallery, user) => {
event.preventDefault();
const { upload_image } = this.state;
firebase
.storage()
.ref(`images/${upload_image.name}`)
.put(upload_image)
.on(
"state_changed",
snapshot => {
// progrss function ....
const progress = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
this.setState({
progress
});
},
error => {
// error function ....
console.log(error);
},
() => {
// complete function ....
firebase
.storage()
.ref("images")
.child(upload_image.name)
.getDownloadURL()
.then(url => {
const newImage = {
description: this.state.gallery_description,
download_url: url,
file_name: this.state.gallery_filename,
id: gallery.length,
uploader_uid: user.uid
};
firebase
.database()
.ref("/gallery/")
.child(gallery.length)
.set(newImage)
.then(() => {
this.context.getGallery();
})
.catch(error => {
console.log(error);
});
});
}
);
};
render() {
return (
<AdminContext.Provider
value={{
...this.state
handleSendImage: this.handleSendImage
}}>
{this.props.children}
</AdminContext.Provider>
);
}
}
Since you're using states, you would need a constructor for your class component and need to bind your methods within the constructor. I suggest you to try the following code:
class AdminProvider extends Component {
static contextType = GalleryContext;
constructor(props) {
super(props)
this.state = {
upload_image: null,
gallery_title: null,
gallery_description: null,
gallery_filename: null,
progress: null
};
this.handleSendImage = this.handleSendImage.bind(this);
}
handleSendImage = (event, gallery, user) => {
event.preventDefault();
const { upload_image } = this.state;
firebase
.storage()
.ref(`images/${upload_image.name}`)
.put(upload_image)
.on(
"state_changed",
snapshot => {
// progrss function ....
const progress = Math.round(
(snapshot.bytesTransferred / snapshot.totalBytes) * 100
);
this.setState({
progress
});
},
error => {
// error function ....
console.log(error);
},
() => {
// complete function ....
firebase
.storage()
.ref("images")
.child(upload_image.name)
.getDownloadURL()
.then(url => {
const newImage = {
description: this.state.gallery_description,
download_url: url,
file_name: this.state.gallery_filename,
id: gallery.length,
uploader_uid: user.uid
};
firebase
.database()
.ref("/gallery/")
.child(gallery.length)
.set(newImage)
.then(() => {
this.context.getGallery();
})
.catch(error => {
console.log(error);
});
});
}
);
};
render() {
return (
<AdminContext.Provider
value={{
...this.state
handleSendImage: this.handleSendImage
}}>
{this.props.children}
</AdminContext.Provider>
);
}
}
Similarly:
class GalleryProvider extends Component {
constructor(props) {
super(props);
this.state = {
gallery: []
};
this.getGallery = this.getGallery.bind(this);
}
getGallery() {
let database = firebase
.database()
.ref("/gallery/")
.once("value")
.then(images => {
console.log(images.val());
this.setState(
{
gallery: images.val()
},
() => {}
);
});
}
componentDidMount() {
this.getGallery();
}
render() {
return (
<GalleryContext.Provider
value={{
...this.state,
getGallery: this.getGallery
}}>
{this.props.children}
</GalleryContext.Provider>
);
}
}
Alternatively, you could use React Hooks inside functional components. Hope this solves your problem.
I would suggest you to read React's documentation on Constructor for more information.

How can I update High Order Component

I created array of routing in ReactJS
const routes = [
{ id: 0, path: '/', view: Home, parent: 0 },
{ id: 1, path: '/a', view: Home2, parent: 0 },
{ id: 2, path: '/b', view: Home3, parent: 1 }
]
Created HOC withAuth which should back to parent routing when user isn't logged. When i going to route (as not logged) - its ok and withAuth back me to parent route, but when i am on route and logout page isn't refresh and I am stay on route for logged users.
import React, { Component } from "react";
import AuthHelper from "./AuthHelper";
export default function withAuth(AuthComponent) {
const Auth = new AuthHelper();
class AuthWrapped extends Component {
constructor(props) {
super(props);
this.state = {
confirm: null,
loaded: false
};
}
checkLogged = () => {
if (!Auth.loggedIn()) {
const parent = this.props.parent;
const obj = this.props.routes
.filter(v => v.id === parent);
this.props.history.replace(obj[0].path);
} else {
try {
const confirm = Auth.getConfirm();
this.setState({
confirm: confirm,
loaded: true
});
} catch (err) {
Auth.logout();
this.props.history.replace("/");
}
}
}
componentDidMount() {
this.checkLogged();
}
render() {
if (this.state.loaded) {
if (this.state.confirm) {
return (
<AuthComponent
history={this.props.history}
confirm={this.state.confirm}
/>
);
} else {
return null;
}
} else {
return null;
}
}
};
return AuthWrapped;
}
I believe that you are using the authentication system the wrong way
In React everything should exist in a hierarchical manner.
In your case, you have an Auth state that would change and when the loggedIn state changes, everything should re-render. the correct way to do this is using the Context API to handle the logged in state so when the state changes, the whole screen would re-render
here is the solution to your problem:
AuthContext.js
const AuthContext = React.createContext();
export class AuthProvider extends React.Component {
state = {
isLoggedIn: false,
};
login = (username, password) => {
someLoginRequestToServer(username, password).then(response => {
this.setState({
isLoggedIn: response.isLoggedIn,
});
});
};
logout = () => {
someLogoutRequestToServer().then(() => {
this.setState({ isLoggedIn: false });
});
};
render() {
return (
<AuthContext.Provider
value={{
loggedIn: this.state.isLoggedIn,
login: this.login,
logout: this.logout,
}}>
{this.props.children}
</AuthContext.Provider>
);
}
}
export const AuthConsumer = AuthContext.Consumer;
SomeCustomAuthComponent
class CustomAuthComponent extends React.Component {
render() {
return (
<AuthConsumer>
{({ loggedIn, login, logout }) => (
<div>
<p>You Are {loggedIn ? 'Logged in' : 'Logged out'}</p>
<button onClick={loggedIn ? () => logout() : () => login('abcd', '12345')} />
</div>
)}
</AuthConsumer>
);
}
}
Or you can use the redux for state management and react-redux as it uses the react Context API under the hood.
hope this helps you! :)
the problem lays here
componentDidMount() {
this.checkLogged();
}
you're checking if the user is logged only when the component is mounted (after the instantiation). you should be checking it every time the page updates, you have to identify a way to handle this mechanism for example by using the componentDidUpdate hook.
export default function withAuth(AuthComponent) {
const Auth = new AuthHelper();
class AuthWrapped extends Component {
constructor(props) {
super(props);
this.state = {
confirm: null,
loaded: false
};
}
checkIsNotLogged = () => {
const parent = this.props.parent;
const obj = this.props.routes
.filter(v => v.id === parent);
this.props.history.replace(obj[0].path);
}
checkLogged = () => {
if (!Auth.loggedIn()) {
this.checkIsNotLogged();
} else {
try {
const confirm = Auth.getConfirm();
this.setState({
confirm: confirm,
loaded: true
});
} catch (err) {
Auth.logout();
this.props.history.replace("/");
}
}
}
componentDidMount() {
this.checkLogged();
}
componentDidUpdate() {
// do not call here the checkLogged method otherwise you could trigger an infinite loop
this.checkIsNotLogged();
}
render() {
if (this.state.loaded) {
if (this.state.confirm) {
return (
<AuthComponent
history={this.props.history}
confirm={this.state.confirm}
/>
);
} else {
return null;
}
} else {
return null;
}
}
};
return AuthWrapped;
}

How to show information from API when using search box in ReactJS?

I'm using the Star Wars API to build a React JS project. The aim of my app is to be able to search for characters.
Here is my code for the search component in the my app.
At the moment I'm able to retrieve data the API and show the information on the page but I can't work out how to show this information when it's searched for.
Any ideas?
import React, { Component } from 'react';
class Search extends Component {
constructor(props){
super(props)
this.state = {
query:'',
peoples: [],
}
}
onChange (e){
this.setState({
query: e.target.value
})
if(this.state.query && this.state.query.length > 1) {
if(this.state.query.length % 2 === 0){
this.componentDidMount()
}
}
}
componentDidMount(){
const url = "https://swapi.co/api/people/";
fetch (url,{
method:'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.map((people) => {
return(
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({peoples: peoples});
console.log("state", peoples)
})
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange.bind(this)}
/>
{this.state.peoples}
</form>
)
}
}
export default Search
You could put your fetch in a separate function instead of in componentDidMount and call that when the component mounts and when your query changes.
Since you might be creating multiple requests if the user types quickly, you could use a debounce to only send one request, or use something that verifies that you always use the result of the latest request, like e.g. a token.
Example
class Search extends Component {
token = null;
state = {
query: "",
people: []
};
onChange = e => {
const { value } = e.target;
this.setState({
query: value
});
this.search(value);
};
search = query => {
const url = `https://swapi.co/api/people?search=${query}`;
const token = {};
this.token = token;
fetch(url)
.then(results => results.json())
.then(data => {
if (this.token === token) {
this.setState({ people: data.results });
}
});
};
componentDidMount() {
this.search("");
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange}
/>
{this.state.people.map(person => (
<ul key={person.name}>
<li>{person.name}</li>
</ul>
))}
</form>
);
}
}
You have to define it in diff function to manage easy.
import React, { Component } from 'react';
class Search extends Component {
constructor(props) {
super(props)
this.state = {
query: null,
peoples: [],
}
}
componentDidMount() {
this.serachPeople(this.state.query);
}
onChange(e) {
this.setState({ query: e.target.value }, () => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query.length % 2 === 0) {
this.serachPeople(this.state.query);
}
} else {
this.serachPeople(this.state.query);
}
})
}
serachPeople(query) {
const url = "https://swapi.co/api/people/";
if (query) {
// if get value ion query so filter the data based on the query.
fetch(url, {
method: 'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.filter(people => people.name === query).map((people) => {
return (
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({ peoples: peoples });
console.log("state", peoples)
})
} else {
fetch(url, {
method: 'GET'
}).then(results => {
return results.json();
}).then(data => {
let peoples = data.results.map((people) => {
return (
<ul key={people.name}>
<li>{people.name}</li>
</ul>
)
})
this.setState({ peoples: peoples });
console.log("state", peoples)
})
}
}
render() {
return (
<form>
<input
type="text"
className="search-box"
placeholder="Search for..."
onChange={this.onChange.bind(this)}
/>
{this.state.peoples}
</form>
)
}
}
export default Search;
I hope this will help for u. Let me know if u have any query.

Categories

Resources